---
title: "Deploy TrailBase"
description: "Single-executable app backend with SQLite, REST APIs and auth"
category: "Other"
url: https://railway.com/deploy/trailbase-api
---

# Deploy TrailBase

Single-executable app backend with SQLite, REST APIs and auth

**[Deploy TrailBase on Railway](https://railway.com/template/trailbase-api)**

Machine-readable deploy manifest (JSON, validated by TemplateCI): https://railway.com/deploy/trailbase-api/manifest.json

- **Creator:** A3A
- **Category:** Other
- **Total deploys:** 1

## Template content

### gateway https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/caddy.svg

- **Image:** caddy:2-alpine
- **Start command:** `/bin/sh -c 'printf %s "$CADDY_CONFIG" > /etc/caddy/config.json; caddy validate --config /etc/caddy/config.json || exit 1; exec caddy run --config /etc/caddy/config.json'`
- **Health check:** /healthz
- **Public domain:** Yes

### trailbase https://cdn.jsdelivr.net/gh/trailbaseio/trailbase@main/assets/favicon.svg

- **Source:** https://github.com/gridalpha/trailbase-railway
- **Health check:** /api/healthcheck

### mailpit https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/mailpit.svg

- **Image:** axllent/mailpit:latest
- **Health check:** /livez
- **Public domain:** Yes

## Buckets

- **trailbase-files**

## Documentation

# Deploy and Host TrailBase on Railway

TrailBase is an open-source application backend that ships as a single executable: a SQLite database, type-safe REST APIs generated from your own tables, realtime subscriptions, email-and-password plus OAuth authentication, a WebAssembly runtime for custom endpoints, and an admin dashboard. It is the Firebase idea reduced to one process — reach for it when you want a backend for a web, mobile or desktop app without running a five-container stack, and when sub-millisecond query latency matters more than write scaling.

Deploy TrailBase on Railway and the whole backend comes up configured. This template runs three services: **trailbase** holds the application and its SQLite depot on a persistent volume, **gateway** is a Caddy reverse proxy owning the public URL that hands TrailBase a correct client IP, and **mailpit** captures the verification and password-reset mail the auth flows send. Uploaded files go to a Railway object-storage bucket rather than the volume, so the disk keeps only databases, config, signing keys and backups. Every browser request enters through the gateway; TrailBase stays on the private network.

![Railway diagram of the TrailBase, gateway and mailpit services](https://res.cloudinary.com/rroe4rtk/image/upload/f_auto,q_auto/v1789471935/trailbase-architecture.webp)

## Getting Started with TrailBase on Railway

Set `ADMIN_PASSWORD` when you deploy — that, plus an optional `ADMIN_EMAIL`, is the only input the template needs. When the deployment goes green, open `/_/admin/` on the gateway's public URL and sign in as `admin@localhost` with the password you chose; the container applies it to the first admin account before the server accepts a request, and records that it has, so a password you change later in the dashboard survives the next deploy. The dashboard opens on a summary of users, tables and database size. Create a table under **Tables**, or write the `CREATE TABLE` in the SQL editor, then use the **API** toggle to expose a record API with world and authenticated access lists. A `GET` on `/api/records/v1/` should now return rows — the quickest confirmation the deployment works. A `TEXT` column with a `CHECK(jsonschema('std.FileUpload', ))` constraint accepts uploads into the bucket. To exercise sign-up, register at `/_/auth/register`, open the mailpit URL — user `admin`, password from `MP_UI_AUTH` — and follow the verification link.

![TrailBase admin dashboard showing user, table and size counts](https://res.cloudinary.com/rroe4rtk/image/upload/f_auto,q_auto/v1789471938/trailbase-admin-dashboard.webp)
![TrailBase table browser listing notes rows with an uploaded attachment](https://res.cloudinary.com/rroe4rtk/image/upload/f_auto,q_auto/v1789471939/trailbase-notes-table-data.webp)
![Running a SQL query against the notes table in TrailBase's editor](https://res.cloudinary.com/rroe4rtk/image/upload/f_auto,q_auto/v1789471940/trailbase-sql-editor-results.webp)

## About Hosting TrailBase

TrailBase collapses the backend-as-a-service stack into one Rust binary over SQLite. The database is in-process, so a query costs no network hop — that is where its sub-millisecond read numbers come from. Self-host it when the app is read-heavy, when the data belongs on infrastructure you control, or when a Postgres-plus-auth-plus-storage stack is out of proportion to the product.

- Record APIs generated from your tables, with per-operation access rules as SQL expressions
- Realtime subscriptions to row changes over SSE
- Auth: email/password, usernames, OAuth, anonymous accounts, TOTP, PKCE for native apps
- A WebAssembly runtime for custom HTTP handlers, scheduled jobs and SQLite functions
- Admin dashboard: table browser, arbitrary SQL, an ER diagram, request logs, user registry
- Typed clients for TypeScript, Dart, Rust, Python, Go, Kotlin, Swift, .NET

**trailbase** is the app; its volume at `/app/traildepot` holds `main.db`, the JWT signing keys and backups, so it must not be removed. **gateway** owns the public origin: TrailBase reads the *last* `X-Forwarded-For` entry, which behind any edge proxy is that proxy's own rotating address, so the gateway rewrites the header to the true client — which is what makes request logs, GeoIP and the per-IP auth rate limit meaningful. **mailpit** is an SMTP sink with a web inbox, since registration fails when verification mail cannot be sent.

## Why Deploy TrailBase on Railway

Railway removes the setup between a single-binary backend and a working URL.

- Volume, object-storage bucket, HTTPS domain and private networking provisioned with the template
- Admin credentials applied before the first request, so no default password is live
- Health checks, restart policies and the reverse proxy pre-wired
- Uploads land in durable object storage, not a fixed-size disk
- Push to the source repository to rebuild and redeploy

## Common Use Cases for Self-Hosted TrailBase

- A backend for a mobile or Flutter app needing auth, a typed API and uploads, without a cloud vendor
- An internal CRUD or admin tool where SQLite is ample and latency invisible
- The API layer for a local-first client that syncs on reconnect

## Dependencies for TrailBase

- **trailbase** — [gridalpha/trailbase-railway](https://github.com/gridalpha/trailbase-railway), a startup script over `trailbase/trailbase:latest` that prepares the volume, the bundled auth-UI WebAssembly component, object storage and the first admin account before the server listens
- **gateway** — `caddy:2-alpine`, configured from a one-line JSON document in a variable
- **mailpit** — `axllent/mailpit:latest`, SMTP on 1025 privately, authenticated inbox on 8025
- **Object storage** — a Railway bucket holding every file uploaded through a record API

### Environment Variables Reference

| Variable | Service | Purpose |
|---|---|---|
| `ADMIN_PASSWORD` | trailbase | Password for the first admin account |
| `ADMIN_EMAIL` | trailbase | Admin identity; default `admin@localhost` |
| `TRAIL_SERVER_SITE_URL` | trailbase | Public URL for mail and OAuth redirects |
| `TRAIL_SERVER_S3_STORAGE_CONFIG_*` | trailbase | Bucket endpoint, region, name, credentials |
| `CADDY_CONFIG` | gateway | Proxy routes and header rewrites |
| `MP_UI_AUTH` | mailpit | `user:password` for the web inbox |

Any scalar field of TrailBase's configuration schema is reachable as `TRAIL_` plus the upper-snake path to it, so `TRAIL_AUTH_DISABLE_PASSWORD_AUTH` needs no config file. Enum fields take their numeric value.

### Deployment Dependencies

- Source: [trailbaseio/trailbase](https://github.com/trailbaseio/trailbase) (OSL-3.0)
- Image: [trailbase/trailbase](https://hub.docker.com/r/trailbase/trailbase)
- Docs: [trailbase.io](https://trailbase.io) and its [production guide](https://trailbase.io/documentation/production)

## Hardware Requirements for Self-Hosting TrailBase

| | Minimum | Recommended |
|---|---|---|
| CPU | 1 vCPU | 2 vCPU |
| RAM | 256 MB | 1 GB |
| Storage | 1 GB volume | 5 GB volume plus object storage |
| Runtime | Linux container | Linux container |

TrailBase is a static musl binary with an embedded database, so idle usage is tens of megabytes. Size RAM for your working set and the WebAssembly runtime, which starts one thread per CPU.

## Self-Hosting TrailBase with Docker

The published image runs unmodified. This starts a server on port 4000 with its depot on a host directory.

```
docker run -p 4000:4000 \
  -v "$PWD/traildepot:/app/traildepot" \
  trailbase/trailbase:latest
```

The depot must be writable by the image's unprivileged `trailbase` user, and the first start prints a generated admin password. To set your own, run the CLI against the same depot first.

```
docker run --rm -v "$PWD/traildepot:/app/traildepot" \
  --entrypoint /app/trail trailbase/trailbase:latest \
  --depot /app/traildepot user change-password admin@localhost 'your-password'
```

Behind a proxy, set `TRAIL_SERVER_SITE_URL` so emailed links and OAuth callbacks point at the right host, and have the proxy send a single-entry `X-Forwarded-For`.

## Is TrailBase Free?

TrailBase is free and open source under OSL-3.0, with no paid tier, seat count or feature gate — every capability in the dashboard is in the binary you run. Self-hosting costs only infrastructure: on Railway you pay for the container, the volume and the bucket, and nothing to the project. It is young software under fast development, so read the changelog before upgrading a deployment holding real data.

## FAQ

**What is TrailBase?**
An open-source backend-as-a-service in one executable: SQLite storage, generated REST APIs, realtime subscriptions, authentication, a WebAssembly runtime and an admin dashboard.

**What does this Railway template deploy?**
Three services — TrailBase on a persistent volume, a Caddy gateway owning the public HTTPS URL, and Mailpit as an SMTP sink with a web inbox — plus a bucket for uploaded files.

**Why does the template include a mail service?**
TrailBase stores a new account's address as unverified and rejects the registration if it cannot send the verification mail, and an unverified user cannot sign in. Mailpit makes sign-up work immediately; point `MP_SMTP_RELAY_*` at a real provider when mail should leave the deployment.

**Why do uploaded files go to object storage instead of the volume?**
A volume is fixed-size and tied to one service, while a bucket grows on demand. TrailBase keeps only file metadata in SQLite and streams the bytes from storage, so the split is invisible to API clients.

**How do I create a REST API from one of my tables?**
Create the table, open it in the dashboard and use the **API** toggle, then set its access lists. Rules are SQL expressions over `_USER_`, `_ROW_` and `_REQ_`, so an ownership check such as `_ROW_.owner = _USER_.id` needs no application code.


## Similar templates

- [Rocky Linux](https://railway.com/deploy/rocky-linux) — Hosted Rocky Linux 9 workspace with SSH and persistent storage. 🚀
- [Foundry Virtual Tabletop](https://railway.com/deploy/X5tR6G) — A Self-Hosted & Modern Roleplaying Platform
- [Letta Code Remote](https://railway.com/deploy/letta-code-remote) — Run a Letta Code agent 24/7. No inbound ports, just deploy.

Open this page in a browser: https://railway.com/deploy/trailbase-api
