Prerequisites
- NodeJS v20.10.0
- NPM v10.2.3 (or similar)
- Go v1.23.1
- Git
- Docker & Docker Compose
Setup Your Repository
Below is an example if you’re working on the Pangolin repository.2
Add upstream remote
Add the remote
upstream:3
Create feature branch
Create a new branch:It is recommended to give your branch a meaningful name, relevant to the feature or fix you are working on.Good examples:
docs-dockerfeature-new-systemfix-title-cards
bugdocsfeaturefixpatch
4
Open pull request
If you open a pull request, open it against the
dev branch of the original repository.Important Best Practices for PRs
- Keep PRs small and single-purpose: One feature, fix, or improvement per PR for easier review and testing.
- Prefer improvements over new features: If you want to propose a net-new feature, contact us by email or on Discord first so we can confirm it fits the roadmap and help scope it.
- Frontend consistency:
- Use existing styles, components, and patterns.
- Use Credenza for modals and Zod for form validation.
- Keep Tailwind classes minimal; prefer component defaults.
- Look for an existing example and mirror that pattern. Extract a small reusable component only when it clearly improves reuse.
- Stick to established patterns: Avoid introducing new architectures or abstractions without discussing them with us first.
- Auth changes require extra care:
- Pangolin is multi-tenant. Handle user controls at the org level (varies by control) or globally via the server admin panel as appropriate.
- Protect all API routes with the correct middleware and verify user permissions and access to referenced entities before performing actions.
- Database changes:
- Keep SQLite and Postgres schemas fully in sync and backward compatible.
- Use datatypes supported by both databases.
- No need to write versioned migrations; maintainers will handle these during releases.
- Add visuals: Include screenshots or short videos when applicable to speed up reviews.
Databases
Pangolin supports two database types: SQLite and Postgres. You can switch between them with the provided scripts: Before running these, read local development setup below.Private Files and Directories
Pangolin includes both AGPLv3 code and some proprietary code licensed under the Fossorial Commercial License. Proprietary files include a license header and often live in directories whose names start withprivate.
You may edit proprietary files in your PR as long as your PR includes the required CLA.
- Frontend: no proprietary code.
- Backend: proprietary code exists, primarily under
server/private/. Subdirectories mirror the structure underserver/.
- AGPLv3 files must never import from the private directory. In TypeScript, the alias
#private/points to proprietary code and should only be used inside other private files. - If you must expose proprietary behavior to AGPLv3 code, use a dynamic import pattern. Create a file that mirrors the proprietary file’s relative location between
server/privateandserver, and ensure the exported APIs have exactly matching function signatures. Dynamic import aliases start with#dynamic. - At build time, depending on the build flag,
#dynamicimports are resolved to the appropriate implementation (AGPLv3 or proprietary).
oss, enterprise, or saas. Enterprise and SaaS include proprietary code; OSS must be 100% AGPLv3 compliant and excludes proprietary code. Use the existing npm scripts to switch:
#dynamic resolves to the correct locations. The build flag is also used in code to conditionally enable or disable features per distribution.
As a rule of thumb, write as much AGPLv3 code as possible. Place only core, distribution-specific functionality in the proprietary layer (Enterprise/SaaS).
Database schemas are never proprietary; all distributions share the same schemas.
If you have any questions about this setup, email us or reach out on Discord.
Pangolin Development Setup
Choose your preferred development approach. We strongly recommend Docker Compose for the most consistent experience across all platforms.Local Development
1
Install dependencies
Install package dependencies:
2
Configure environment
Ensure you have a
config/ directory at the root with a config.yml inside. Refer to the Pangolin Configuration docs or the config.example.yml in the repo for a sample of what to include in that file.3
Set your environment
Choose to build from the oss/enterprise/saas codebase:Then choose your database:
4
Generate database schema
Generate the database schema and push it:
5
Start development server
Start the development server using Docker Compose:Or, start the development server directly:
Exit Nodes
When running Pangolin for the first time there will be no exit nodes. This means that there have been no Gerbil “exit nodes” registered in the database, and therefore, you cannot create Newt sites. When Gerbil first starts up and requests its config from Pangolin for the first time it gets registered as an exit node. The easiest way to resolve this is to run Gerbil and have it register in your dev environment. Download the Gerbil binary and run it with localhost:Windows Development Considerations
- WSL2 Filesystem (Recommended)
- Windows Filesystem + Polling (Workaround)
Best performance and compatibilityReference Links
-
Where to store your project files:
- For best performance, always store your project inside the Linux filesystem of your Docker or Default WSL2 instance, e.g.
/home/<user>/pangolin. - If other WSL instances are used, ensure the Docker Desktop WSL integration is enabled for that distribution.
- For further information, see Link Section below.
- For best performance, always store your project inside the Linux filesystem of your Docker or Default WSL2 instance, e.g.
-
Accessing WSL2 files from Windows:
- You can access your WSL2 home directory from Windows using the UNC path:
\\wsl$\<DistroName>\home\<user>\pangolin(replace<DistroName>with your actual WSL distribution, e.g.Ubuntu-22.04). - This path works in Windows Explorer, VS Code, and other Windows applications. You can drag & drop files, create shortcuts, or map a network drive for convenience.
- Note: This UNC path is for Windows tools only. Do not use it for Docker container mounts.
- You can access your WSL2 home directory from Windows using the UNC path:
-
How to mount WSL2 files in Docker containers:
- Always use the absolute Linux path from inside WSL2 for Docker volumes. This is the only method fully supported and recommended by Docker.
- Correct Docker Compose example:
- Correct docker run example:
- Never use
\\wsl$or Windows paths (e.g./mnt/c/...) for Docker volumes when running with the WSL2 backend. This is not supported and can lead to poor performance or errors. - File watchers and hot reload works natively when your project is inside the WSL2 filesystem and mounted using the Linux path.
You may want to use the VS Code Remote - WSL extension or VS Code Remote - SSH Extension to open your project folder directly in VSCode from the WSL/Remote Filesystem for seamless Development.
Component Development
Gerbil
- Go v1.23.1
Newt
- Go v1.23.1
Olm
- Go v1.23.1

