Requirements
The runtime, database, scheduler, email and provider accounts Subsweep needs, which keys are optional, and a server sizing starting point.
4 min readUpdated Oct 17, 2026Applies to Subsweep 0.1.0
On this page
At a glance
| You need | Required for | Notes |
|---|---|---|
| Node.js 20.9 or newer | Everything | Next.js 16 requires 20.9+. Node 22 LTS is a good default. |
| PostgreSQL 13 or newer | Production | The schema uses the built-in gen_random_uuid(), available from Postgres 13. Without a database URL the app will not build or serve pages in production. |
| A host for a Next.js app | Production | Vercel (the package ships a vercel.json) or your own server running next start behind HTTPS. |
| An hourly scheduler | Reminders, alerts, digests, bank sync | Vercel Cron, or a cron job on your server that calls /api/cron/tick. Nothing in the app schedules itself. |
| HTTPS on your own domain | Production | Sign-in cookies, OAuth redirects and Stripe return links all use your public URL. |
| Outbound email | Production | Any SMTP account or Resend. Without it, production refuses email sign-up (unless ALLOW_UNVERIFIED_SIGNUP=true) and magic links, and invites cannot reach anyone. |
| Stripe account | Optional | Only to charge customers for Pro and Accountant plans. The webhook needs its signing secret, STRIPE_WEBHOOK_SECRET. |
| Plaid, Google, Microsoft and other developer accounts | Optional | Each integration switches on when its keys are set. See Integrations. |
Hosting options
Subsweep is a standard Next.js server application. It can run in two shapes:
- Vercel with a managed Postgres (Neon, Supabase and similar). This is how the package is configured:
vercel.jsonregisters an hourly cron for/api/cron/tick, and the database client is tuned for serverless (one connection per function instance, prepared statements off so it works through a transaction pooler). - Your own server (a VPS, or Docker). Run
npm run buildandnpm startbehind a reverse proxy that terminates HTTPS, and add a cron entry for the hourly job. Installation and deployment has both paths.
Important
next build needs the full production environment and a reachable database. Several pages are pre-rendered during the build, and that touches the database, so a build without DATABASE_URL (or with an unreachable one) fails. Plan your pipeline so the build can reach Postgres.
Database
- Postgres 13 or newer. No extensions are needed. Tested on Postgres 18; the bundled
docker-compose.ymluses Postgres 16. - Any provider. Self-hosted, Neon, Supabase, RDS and similar. The app connects with the
postgres(postgres.js) driver over TCP and accepts pooled URLs. - The schema creates itself. There is no separate migration command. On the first database access of each server process (and during the build), the app runs
lib/db/bootstrap.sql(CREATE TABLE IF NOT EXISTS ...) plus a short list of additive patches. The database user therefore needs permission to create tables in its schema. See Database schema and updates. - Local development needs no database server. Without a database URL in development, the app uses embedded PGlite stored in
.data/subsweep, which survives restarts.
Note
In production each server process opens exactly one database connection. That suits serverless functions; on a single long-running server it means requests share one connection and wait their turn. It is fine for a small install; see Known limitations.
Domain and HTTPS
Subsweep does not terminate TLS itself. On your own server, put it behind Caddy, nginx with Let's Encrypt, a load balancer or your platform's HTTPS.
Set BETTER_AUTH_URL to the exact public origin (for example https://subs.example.com). It is used for:
- sign-in, verification and magic-link URLs, and the trusted origin check (the
www.and bare variants of the host are both trusted); - every OAuth redirect URI (Google, Gmail, Outlook, Slack, QuickBooks, Xero, TrueLayer);
- Stripe Checkout success and cancel URLs, and links in emails.
Provider accounts
| Provider | What it powers | Required? |
|---|---|---|
| SMTP server or Resend | Verification, magic links, invites, alerts, digests | Yes in production, for email sign-up and magic links |
| Stripe | Pro and Accountant checkout, customer portal | Only to charge customers |
| Plaid | US and Canada bank feeds | Optional |
| Google Cloud | Google sign-in and Gmail receipt scanning | Optional |
| Microsoft Entra | Outlook receipt scanning | Optional |
| Slack | Connecting a Slack channel | Optional, see the note on Slack |
| Open Exchange Rates | Live exchange rates | Optional; built-in fallback rates otherwise |
The full list, with what each one does in version 0.1.0, is on Integrations.
Warning
Gmail read-only access (gmail.readonly) is a restricted Google scope. Letting the public connect their Gmail requires Google's verification and a security assessment, which takes time and can cost money. Read Google's restricted scope requirements before you promise Gmail scanning to customers.
Server size
These figures are guidance, not a measured benchmark. Subsweep does no heavy computation apart from parsing an uploaded statement and the hourly job.
| Workload | Suggested starting size |
|---|---|
| Evaluation or a single business | 1 vCPU, 1 GB RAM, plus a managed or small local Postgres |
| A small SaaS with a few hundred workspaces | 2 vCPU, 2 to 4 GB RAM |
| Growing beyond that | Watch how long the hourly job takes (it walks every workspace in one request) before adding hardware |
next build uses noticeably more memory than the running app. On a 1 GB server, add swap or expect the build to be slow.
What the browser loads from elsewhere
- Vendor logos. 49 vendors have a bundled SVG logo. For other vendors the browser loads a favicon from Google's favicon service (
www.google.com/s2/favicons). - Plaid Link loads from
cdn.plaid.comwhen someone connects a bank. - Sentry's browser bundle loads from its CDN only if you set a Sentry DSN.
Local development
For a laptop install you only need Node.js and npm. Postgres, keys and a domain can all come later. Quick start walks through it.