Database per branch, no shared state
Two worktrees. Same myapp_dev database. One runs a migration, the other’s schema breaks. Treeline can give every worktree its own database — cloned from a template in seconds, seeded from hooks, or copied as a SQLite file. Database isolation is opt-in: omit the database block entirely if your project doesn’t need it.
Option A: Clone from a template (PostgreSQL)
PostgreSQL’s createdb --template copies the full schema and data from an existing database without running migrations or seeds. If your template database is ready to go, a new worktree gets a complete database in seconds — even if your seed file takes 20 minutes.
The trick: keep your template database up to date. If you maintain a clean, seeded template (e.g. after each migration, re-seed the template), every clone starts from a known-good state. Your CI can do this, or a post_setup hook on the main worktree can keep it fresh.
project: myapp
database:
adapter: postgresql
template: myapp_development
pattern: "{template}_{worktree}"
env:
PORT: "{port}"
DATABASE_URL: "postgresql://localhost:5432/{database}" $ gtl new feature-auth
Creating worktree feature-auth
Allocated port 3012
Cloned database myapp_development_feature_auth
Wrote .env.local
==> https://myapp-feature-auth.prt.dev
The {database} token in the env block resolves to the cloned database name. The pattern field controls the naming: myapp_development_feature_auth in this example. The template database is never modified.
Managing worktree databases
# Print the worktree’s database name
$ gtl db name
myapp_development_feature_auth
# Drop and re-clone from the template
$ gtl db reset
# Clone from a different source instead
$ gtl db reset --from staging_snapshot
# Restore from a pg_dump file (auto-detects format)
$ gtl db restore dump.sql
# Clean up when done
$ gtl release --drop-db
Option B: Seed from hooks (no template)
If your team prefers running migrations + seeds on every new worktree instead of maintaining a template, skip the database block and use commands.setup to create the database from scratch.
project: myapp
env:
PORT: "{port}"
DATABASE_NAME: "myapp_dev_{worktree}"
commands:
setup:
- bin/rails db:create
- bin/rails db:schema:load
- bin/rails db:seed This approach trades setup speed for simplicity — no template to maintain, every worktree starts from the current schema. If your seed file is slow (10+ minutes), consider Option A instead. If it’s fast or you’re using a framework like Prisma that handles migrations differently, this may be all you need.
You can also combine the two: clone from a template for the schema, then run lightweight data patches in commands.setup.
Option C: SQLite (file copy)
SQLite databases are files. Treeline clones by copying the file to the worktree directory. No server, no createdb.
project: myapp
database:
adapter: sqlite
template: db/development.sqlite3 Port-dependent data
If your database stores URLs that include the port — OAuth redirect URIs, webhook endpoints, asset URLs — the cloned data will have stale values pointing to the template’s port. Use commands.setup to patch them after cloning:
commands:
setup:
- psql $DATABASE_URL -c "UPDATE settings SET base_url = 'http://localhost:$PORT'"
Setup commands run after the env file is written, so $PORT and $DATABASE_URL are already available.
When to use which
| Approach | Speed | Best when |
|---|---|---|
| Clone from template | Seconds | Seed is slow, team maintains a clean template database |
| Seed from hooks | Varies | Seed is fast, or team uses migrations (Prisma, Knex) instead of templates |
| SQLite file copy | Instant | App uses SQLite — no server needed |
| No database config | — | App doesn’t use a local database, or databases are managed externally |
Read next
- Isolation feature page — ports, databases, Redis, and env file management
- Docs: configuration — full
.treeline.ymlreference with all database options - Docs: database guide — cloning, naming, and
gtl dbcommands