Open-source project
outline/outline avatar
outline/outline

Outline v1.10.1: BSL 1.1, a duplicated image link, and a dev script bound to 0.0.0.0

GitHub describes it as The fastest knowledge base for growing teams. Beautiful, realtime collaborative, feature packed, and markdown compatible.. The repository metadata lists TypeScript as its primary language. The metadata lists the NOASSERTION license. This article stays within the project description and details documented in the GitHub repository README.

40,778 stars3,597 forksTypeScriptNOASSERTION

At a glance

What is it?
Outline is a self-hostable, collaborative knowledge base written in TypeScript, with React on the front and Node.js behind it, and it is offered both as a hosted product and as source. The details that decide whether a self-host works are in the tooling: the image list names one link twice, the development command opens the Node inspector on every interface, the install step rewrites node_modules, translations are extracted during the build, and the license is BSL 1.1 rather than an open source grant.
Who is it for?
Outline fits a team that wants a hosted wiki today and the option to run the same code later, provided someone owns the deployment: the production path is the hosting documentation plus a container image, the schema changes are handled by Sequelize with a rollback, and the configuration surface is documented in .env.sample down to the file-based secret convention.
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 received new commits within the last day.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

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

Editorial analysis

The image list repeats one link twice and names no tag

The installation section is two lines long. It sends you to the hosting documentation for running your own copy in a production configuration, and then lists available container images as two bullets that both point at the same Docker Hub repository, outlinewiki/outline. Nothing states a version, a tag, or a digest, and the two bullets are indistinguishable.

The repository tree explains where the second name comes from: alongside the Dockerfile there is a Dockerfile.base, and the Dockerfile itself takes a base image argument defaulting to outlinewiki/outline-base before it copies the built application into a node runner. So the published image and the build-time base are two different artifacts, and only one of them is named on the front page.

Consequence for you: there is no way to tell from this page which image to pull for a given release, and an unpinned pull gives you whatever is newest. Pin a tag or digest yourself, and read the hosting documentation before assuming the compose file in the repository is a production arrangement.

The development command opens the Node inspector on every interface

The dev script in the package manifest runs the built server under the Node inspector, bound to all interfaces:

code
"dev": "NODE_ENV=development yarn concurrently -n api,collaboration  -c \"blue,magenta\" \"node --inspect=0.0.0.0 build/server/index.js --services=cron,collaboration,websockets,admin,web,worker\"",

The inspector is a debugging protocol that allows code execution in the process, and 0.0.0.0 is every network interface rather than localhost.

Consequence for you: run this script on a laptop and nothing is exposed. Run it on a shared development box, a container with a published port, or a cloud instance, and the debugger is reachable from wherever the port is routed, which is a code execution path into the application and everything it holds. Use the script locally, or override the bind address before using it anywhere else.

Six services share one Node process in development

The same dev command starts a single node process with an explicit service list: cron, collaboration, websockets, admin, web, and worker. The concurrently wrapper names two of them, api and collaboration, which is the two things a developer sees in the terminal, while the rest of the list is the same process under other hats.

In production that split is configurable rather than fixed. The environment sample describes COLLABORATION_URL as the setting for running a separate collaboration server, with a pointer to the services documentation, and notes that for normal operation it does not need to be set at all. The file also carries WEB_CONCURRENCY, described as how many processes to spawn, with a rule of thumb of dividing available memory by 512.

Consequence for you: a development run has the web server, the cron runner, the collaboration service, and the background worker in one event loop and one memory budget, so a stuck job shows up as a slow site. Anyone copying a dev command onto a server inherits that coupling unless they split the services the way the configuration allows.

yarn install rewrites node_modules before anything runs

The postinstall script is `yarn patch-package`, and the repository carries a patches/ directory at the top level. The prepare script is `husky install`, with a .husky/ directory and a lint-staged configuration alongside it, so an ordinary install also wires up the commit hooks.

Consequence for you: the dependency tree you get is not exactly the one the lockfile names, because patched files are applied on top of the installed packages after resolution. Builds that skip lifecycle scripts, which hardened CI images and some caching strategies do by default, will install the unpatched dependencies and can differ from a developer machine in ways no lockfile check will reveal. Keep the patches directory with any fork you make, and if you need a reproducible install, verify that scripts are actually running.

Translations are extracted during the build, not at runtime

Translation work is a build step. The i18n build script runs the extractor over shared, app, server, and plugins with a silent flag and a brace pattern covering .ts and .tsx files, then a second script copies the locale directories into the build output at build/shared/i18n. The full build runs clean, the Vite build, the i18n build, and the server build in that order. The repository also carries crowdin.yml and links a translation service, and the contributing section lists translation into other languages as a supported way to help, with a guide at docs/TRANSLATION.md.

Consequence for you: a missing or renamed key is not caught at edit time, it surfaces after a complete build, and the strings that ship are the ones the extractor found in the four source trees. Anyone adding a user-facing string needs to run the build to see whether it made it into the catalogues, and a translator working from the service is working against output that only exists after that run.

make test creates the test database before vitest can run

The suite has two entry points, and the order matters. The documented commands are:

shell
# To run all tests
make test

# To run backend tests in watch mode
make watch

Once that first command has created the test database, individual suites can be run directly with vitest: yarn test:server for the backend, yarn test:app for the frontend, and yarn test path/to/file.test.ts --watch for a single file. Tests are written in Vitest and live in a .test.ts file next to the code they cover. The stated coverage goal is deliberate rather than maximal: sufficient coverage of the critical parts, not 100 percent unit coverage, with all API endpoints and anything authentication related expected to be thoroughly tested.

Consequence for you: a fresh clone cannot run yarn test:server first and debug the failure later, because the database has to exist. The policy also tells you where review attention goes, which is the API surface and authentication, and where it does not.

Sequelize migrations carry a rollback and a test environment

Schema changes are managed with Sequelize, and the three commands are named explicitly: create a migration with a name, apply it, and roll it back.

shell
yarn db:create-migration --name my-migration
yarn db:migrate
yarn db:rollback

A fourth form targets the test database instead, appending an environment selector to the same migrate command. The supporting files are in the tree: a .sequelizerc for the CLI configuration, and three committed environment files, .env.sample, .env.development, and .env.test, which is how the production, development, and test configurations stay separate.

Consequence for you: a rollback path exists, which is more than many projects offer, but it is one step and not a plan, and an irreversible data change still needs its own recovery thinking. Since the environment files are committed, the risk sits in what a developer adds to .env.development or .env.test, which are not covered by the sample file's documentation.

Secrets can live in files, and the direct variable wins

The environment sample documents a convention that matters for container deployments: any variable Outline reads can instead be loaded from a file by appending _FILE to its name and pointing at the path, which the sample frames as useful for Docker secrets. Two rules follow. The file contents are trimmed of leading and trailing whitespace, and if both forms are set, the direct variable takes precedence.

The same file spells out the values that change behaviour. URL must be the fully qualified public URL, or the proxy URL if one is in front. PORT is 3000 and is noted as needing to match docker-compose.yml. CDN_URL rewrites the paths to javascript, stylesheets, and images, and the origin server in your CDN should be set to the same value as URL. SECRET_KEY is documented with the command to generate a hex-encoded 32 byte random key.

Consequence for you: precedence cuts both ways, since a stale direct variable silently overrides the file you think is in charge, and a key rotation that only writes the _FILE variant will not take effect. Get the precedence right before you rotate anything.

Editorial conclusion

Outline fits a team that wants a hosted wiki today and the option to run the same code later, provided someone owns the deployment: the production path is the hosting documentation plus a container image, the schema changes are handled by Sequelize with a rollback, and the configuration surface is documented in .env.sample down to the file-based secret convention. It does not fit someone who needs an OSI open source grant, since the license is BSL 1.1, and it does not fit a contributor who wants to land a generated pull request, since the project asks for none. Before you commit, read the LICENSE file rather than the metadata field, keep the dev command off any shared host, and confirm the image tag you intend to pin, because the front page names the image twice and never names a version.

Frequently asked questions

how to install outline server on ubuntu

The README gives no per-OS steps. It points to the hosting documentation for running your own copy in a production configuration and to the container image published as outlinewiki/outline, and it links a short guide for setting up a development environment. The repository also ships a docker-compose.yml with Redis and PostgreSQL bound to 127.0.0.1 on their default ports.

What license is Outline released under?

The README states that Outline is BSL 1.1 licensed and points to the LICENSE file in the top level directory, and the package manifest declares the same Business Source License 1.1. The repository metadata reports the license as NOASSERTION, so automated license scanners will not resolve a standard identifier from it.

Does Outline accept pull requests written by AI coding tools?

No. The contributing section asks that AI-generated pull requests not be submitted, explaining that the project receives a high volume of mass, low-quality pull requests generated by tools like Claude, ChatGPT, and Copilot from contributors unfamiliar with the codebase, that these are almost never mergeable, and that they waste maintainer time.

What does Outline require before you write any code for it?

You must first discuss with the core team by creating or commenting in an issue on GitHub, or in the discussions, so that an approach is agreed before code is written. The stated reason is a much higher likelihood that your code is accepted, and the listed ways to help include translation, issues labelled good first issue, performance work on the server and frontend, and documentation.

How do you run the Outline test suite?

Run make test to run everything and create the test database, then use vitest directly: yarn test:server for the backend, yarn test:app for the frontend, and yarn test path/to/file.test.ts --watch for one file. Tests are written with Vitest in a .test.ts file next to the tested code, and the project aims for coverage of critical parts rather than full unit coverage.

Official sources

  1. Official documentation
  2. Official README
  3. Project repository
  4. Release notes
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/outline-outline.svg)](https://hysenlabs.com/projects/outline-outline)