Model or dataset
investbrainapp/investbrain avatar
investbrainapp/investbrain

Investbrain: a self-hosted PHP investment tracker with pluggable market data and an LLM chat layer

Smart LLM-enabled investment tracker that consolidates and monitors market performance across your different brokerages

929 stars72 forksPHPNOASSERTION

At a glance

What is it?
Investbrain is a Laravel application that consolidates brokerage holdings, pulls quotes from configurable market data providers, and lets you query your portfolio through an LLM. The Docker Compose path is the documented install; the AI chat is off by default.
Who is it for?
Adopt Investbrain if you already run Docker Compose, want portfolio and transaction data in a Postgres instance you control, and are comfortable editing environment variables rather than clicking through a settings UI. Do not adopt it if you need a vendor to hold your API keys, if you cannot maintain a PHP/Laravel container, or if you expect the AI chat to be useful without configuring a provider key first.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 37 days ago.
What is it written in?
Mainly PHP, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 27, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem Investbrain solves: holdings scattered across brokerages

Most people who hold investments for a few years end up with positions in more than one place. A brokerage account here, an employer plan there, maybe a second broker opened for a specific fee structure. Each one reports performance in its own format, on its own schedule, with its own definition of cost basis. Investbrain's stated purpose is to consolidate that: the repository description calls it a "Smart LLM-enabled investment tracker that consolidates and monitors market performance across your different brokerages." The target user is someone who wants a single view and is willing to run the software themselves. That last clause matters more than the feature list. Investbrain ships as a Docker image and a Compose file, and the README's install path assumes Docker Engine is already present. This is not a hosted service you sign up for. It is an application you operate, which means your transaction history and your brokerage credentials stay on hardware you control, and also that nobody else is on the hook when a container stops.

Laravel, Postgres, Redis: the architecture behind the portfolio view

The README describes Investbrain as "a Laravel PHP web application that has an extensible market data provider interface." The compose file fills in the rest of the stack. Three services run: the app container (investbrainapp/investbrain:latest, listening on port 80 inside the container and mapped to 8000 on the host), a postgres:15-alpine database, and redis:alpine. The app container's environment sets SESSION_DRIVER, QUEUE_CONNECTION and CACHE_STORE all to redis, so sessions, background jobs and caching share that one Redis instance. Market data refresh is driven by a queue, and the refresh cadence is configurable through MARKET_DATA_REFRESH, which the .env.example documents in minutes with a default of 30. Persistent state lives in three named volumes: investbrain-storage, investbrain-redis and investbrain-pgsql. The frontend is a Vite build with Alpine.js and ApexCharts, per package.json, which is consistent with the chart-heavy screenshot in the README. The design choice worth noticing is that the market data layer is an interface, not a hardcoded client. The README points to app/Interfaces/MarketData/MarketDataInterface.php and says you can implement your own provider, register it in the config file under an interfaces key, and add its name to the MARKET_DATA_PROVIDER list. That is a real extension point rather than a marketing bullet, and it is the main reason this project is worth a second look over a closed tracker.

Installing Investbrain with Docker Compose

The README recommends Docker Compose as the install method and says the provided compose file uses the official image with all dependencies included. You need Docker Engine first. Then fetch the compose file:

bash
curl -O https://raw.githubusercontent.com/investbrainapp/investbrain/main/docker-compose.yml

The README's next step is to adjust the environment properties in the compose file to your preferences. The compose file carries a comment that you use either those inline environment properties or an .env file, but not both, so pick one. The inline defaults point at the investbrain-pgsql host with database, user and password all set to investbrain, and set APP_URL to http://localhost:8000. If you would rather drive configuration from .env, the .env.example lists the full set, including APP_KEY, which it says to generate with openssl rand -base64 32, and REGISTRATION_ENABLED, which defaults to true. Once configuration is settled:

bash
docker compose up

The README notes this may take a few minutes while images pull. When it finishes, the documented first-run URL is http://localhost:8000/register. Seeing the registration form there is the signal that the app, database and Redis all came up. Register the first account, then add a portfolio and transactions. If you want the AI chat, it is disabled by default: AI_CHAT_ENABLED is false in .env.example. Turning it on requires an API key from a supported lab, or a local endpoint if you are running something like Ollama behind an OpenAI-compatible API. The README is direct about the caveat attached to that feature: "Always keep in mind the limitations of LLMs. When in doubt, consult a licensed investment advisor."

Market data providers and the fallback chain

Quote retrieval is the part of Investbrain most likely to break in practice, because it depends on third parties you do not control. The README lists Yahoo Finance, Twelve Data, Finnhub, Alpaca and Alpha Vantage as supported providers, and describes a fallback mechanism: if a provider fails, the application tries the next one in the list. Configuration is a single comma-separated environment variable. A single provider looks like this:

bash
MARKET_DATA_PROVIDER=yahoo

A fallback chain looks like this:

bash
MARKET_DATA_PROVIDER=yahoo,alphavantage

The README states that in the second example Yahoo Finance is attempted first, and if it fails to retrieve market data, Alpha Vantage is tried next. Keys for the paid or rate-limited providers live in the .env.example under names like ALPHAVANTAGE_API_KEY, FINNHUB_API_KEY, ALPACA_API_KEY, ALPACA_API_SECRET and TWELVEDATA_API_SECRET. The honest reading of this design is that it moves the failure mode rather than removing it. If Yahoo is your only provider and it starts returning errors, you have no quotes until you change the variable and restart. Setting up two providers from the start is cheap insurance, and the README treats the comma-separated form as the intended way to use it. Custom providers follow the same pattern: implement MarketDataInterface, register the class under the interfaces key in the config file, and append its name to MARKET_DATA_PROVIDER. The README invites pull requests for providers you write, though it does not document a review timeline or a provider certification process.

Import, export and what happens on a re-import

Investbrain supports importing and exporting portfolios and transactions, and the README describes the import semantics precisely enough to plan around. Imports are upserted. If a record does not exist, it is created. If a portfolio or transaction already exists, meaning the record's ID matches an existing record, the record is updated. This is the behaviour you want for a recurring sync from a brokerage export, but it has a sharp edge: matching is by ID, not by a natural key such as date plus symbol plus quantity. If your export source regenerates IDs on each run, the upsert will not recognise the row as an update and you will get duplicates instead. The README does not document how IDs are assigned on import, and it does not describe a deduplication pass. Before you build any automated pipeline on top of this, import the same file twice into a throwaway portfolio and count the rows. That single test tells you more about whether the import path fits your workflow than any feature description. The README's export section is truncated in the repository listing, so treat export as a documented feature whose exact format you should confirm in the app rather than assume.

Where Investbrain is the wrong tool

The largest limitation is operational. Every provider key, every LLM key and the entire transaction history sit in your environment and your volumes. If you are not prepared to patch a container, watch for upstream image changes and keep backups of investbrain-pgsql and investbrain-storage, a self-hosted tracker is a worse choice than a hosted one, not a better one. The compose file mounts storage as a volume separate from the database volume, so a backup routine that only dumps Postgres is incomplete. Second, the AI chat is optional and off by default, and enabling it means sending portfolio context to whichever lab you configure, or running a local model that may not be strong enough to be useful. The README's own warning about LLM limits is the correct framing: this is a thought partner, not advice. Third, Investbrain is a tracker, not a brokerage integration. Nothing in the repository documentation suggests it places trades or connects to broker APIs for execution; the data path is import plus market data providers. If you want automatic position sync from your broker without exporting files, this is not that. Finally, the licence is listed as NOASSERTION in the repository metadata. That means the licence could not be automatically classified, not that there is no licence. LICENSE.md exists at the repository root, and you should read it yourself before using Investbrain commercially or redistributing the image.

How it compares to Ghostfolio and Wealthfolio

The related searches around Investbrain are dominated by comparisons with Ghostfolio and Wealthfolio, and the differences are structural rather than cosmetic. Ghostfolio is also a self-hosted portfolio tracker, but it is built on Node.js and NestJS rather than Laravel, so the operational surface you inherit differs: different runtime, different container layout, different upgrade path. If your team already runs PHP and Laravel services, Investbrain's stack will be familiar to the people who have to keep it alive, and that is a legitimate reason to prefer it over a functionally similar Node application. Wealthfolio takes a different approach again, shipping as a desktop application rather than a server you host, which removes the container maintenance burden entirely and changes the privacy model: your data lives on the machine you run it on, with no Postgres and Redis to back up. The trade-off is that a desktop app is not reachable from a phone browser or a second machine without extra work. Investbrain sits in the middle: server-hosted, browser-accessible, with the maintenance obligations that come with that. The custom market data provider interface is Investbrain's clearest differentiator against both, because it lets you plug in a data source the maintainers have never heard of without forking the application.

Maintenance, upgrades and licence questions to settle first

The repository is not archived, and the last push was on 2026-08-24. Releases are reasonably paced: v1.2.8 on 2026-03-15, v1.2.9 on 2026-03-25, and v1.3.0 on 2026-06-26. The README has an Updating section in its table of contents, which means the project documents an upgrade path rather than leaving you to guess, though the section body is not included in the repository listing, so read it in the repository before you upgrade a live instance. Because the compose file pins the image tag to latest, an unattended docker compose pull will move you to whatever was published most recently. If you want controlled upgrades, pin the image to a specific version tag and bump it deliberately alongside a database backup. On licence, the repository metadata reports NOASSERTION, so the automated classifier could not determine the terms. LICENSE.md is present at the root. Read it before you build anything commercial on top of Investbrain or redistribute the image to others. Nothing here is legal advice, and the licence file is the only authority.

Editorial conclusion

Adopt Investbrain if you already run Docker Compose, want portfolio and transaction data in a Postgres instance you control, and are comfortable editing environment variables rather than clicking through a settings UI. Do not adopt it if you need a vendor to hold your API keys, if you cannot maintain a PHP/Laravel container, or if you expect the AI chat to be useful without configuring a provider key first. Before committing, verify three things: that your chosen market data provider covers the symbols you hold, that MARKET_DATA_PROVIDER is set to a comma-separated list rather than a single value if you want the documented fallback behaviour, and that your backup process captures the investbrain-storage volume alongside the Postgres volume, since the compose file mounts them separately.

Frequently asked questions

How do I install Investbrain?

The README recommends Docker Compose. Download the compose file with curl, adjust the environment properties to your preferences, then run docker compose up. Once the images pull, the documented first-run URL is http://localhost:8000/register.

Does Investbrain need an OpenAI key to work?

No. The AI chat feature is disabled by default, with AI_CHAT_ENABLED set to false in .env.example. Portfolio tracking and market data work without any LLM provider configured; you only need a key if you turn the chat on.

What happens if my market data provider fails?

Investbrain has a fallback mechanism. If you list providers separated by commas in MARKET_DATA_PROVIDER, the README states it will try each in order until one returns data successfully. A single provider gives you no fallback.

Can I add a market data provider that Investbrain does not support?

Yes. The README says you can implement the MarketDataInterface, register your class under the interfaces key in the Investbrain configuration file, and then append your provider name to the MARKET_DATA_PROVIDER environment variable.

What happens if I import the same transactions twice?

Imports are upserted. The README says a record is created if it does not exist, and updated if its ID matches an existing record. Because matching is by ID rather than a natural key, re-importing a file whose IDs change can create duplicates.

Official sources

  1. investbrainapp/investbrain on GitHub
  2. Issues
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/investbrainapp-investbrain.svg)](https://hysenlabs.com/projects/investbrainapp-investbrain)