If you’re building a serious app with Claude Code, sooner or later you’ll need a database. For most projects, the right answer is PostgreSQL. This guide walks through how to set up a PostgreSQL database for a Claude Code app on Linux, with enough detail to avoid the usual traps: weak permissions, bad connection strings, messy migrations, and backups that only exist in theory.
This is written for people who already know their way around a shell and want a practical setup they can trust in production. If you’re hosting in a sandboxed Linux environment like Vibesies, the same principles apply: keep credentials isolated, make backups automatic, and let your agent do the repetitive parts without turning your app into a science project.
Why PostgreSQL is usually the right choice for Claude Code apps
Claude Code can help you build with almost any storage layer, but PostgreSQL tends to be the safest default for real apps. It handles relational data well, supports JSON when you need flexibility, and scales from a side project to a production system without forcing a rewrite.
It’s a good fit if your app needs any of the following:
- User accounts and authentication
- Orders, subscriptions, or billing records
- Content management with relationships
- Event logs, audit trails, or activity feeds
- Searchable metadata with a mix of structured and semi-structured data
If your app is truly static, you may not need a database yet. But once you’re storing anything that must survive restarts and scale beyond a single file, PostgreSQL is usually the cleanest option.
How to set up a PostgreSQL database for a Claude Code app
Here’s the setup I recommend for most Linux-hosted apps:
1. Install PostgreSQL
On Ubuntu or Debian:
sudo apt update
sudo apt install postgresql postgresql-contrib
Confirm it’s running:
sudo systemctl status postgresql
On a managed environment, PostgreSQL may already be available. In that case, skip the install step and focus on creating a dedicated database and user.
2. Create a dedicated database and user
Do not use the default postgres superuser for your app. Create a separate user with only the permissions it needs.
sudo -u postgres psql
Then inside the PostgreSQL prompt:
CREATE DATABASE myapp;
CREATE USER myapp_user WITH ENCRYPTED PASSWORD 'use-a-strong-password';
GRANT ALL PRIVILEGES ON DATABASE myapp TO myapp_user;
If your app has a migration tool that needs schema ownership, you may also want to make the app user the owner of the database:
ALTER DATABASE myapp OWNER TO myapp_user;
That keeps migrations clean and avoids permission errors later.
3. Store the connection string in an environment variable
Use a single database URL rather than hardcoding values in your app:
DATABASE_URL=postgresql://myapp_user:password@127.0.0.1:5432/myapp
For local development, this might live in a .env file. In production, put it in your process manager, secret store, or platform-level environment config. The important thing is that it stays out of git.
4. Test the connection before wiring up the app
Check that PostgreSQL is reachable with the same credentials your app will use:
psql "$DATABASE_URL"
If that works, your app should be able to connect too. If it doesn’t, fix the database credentials before you start debugging your app code. You’ll save time.
5. Hook up migrations
Most Claude Code apps will need migrations as soon as the schema changes. Use whatever migration tool matches your stack:
- Flask / Python: Alembic or Flask-Migrate
- Django: built-in migrations
- Node.js: Prisma, Knex, or your ORM’s migration tool
The main rule: migrations should be versioned, repeatable, and committed to your repo. Claude Code can generate them, but you should still review them before applying changes to production.
Common PostgreSQL setup mistakes with AI-built apps
Claude Code is good at generating application logic, but database setup is where small omissions become production problems. These are the mistakes I see most often.
Using a superuser for the app
This is the classic “works on my machine” shortcut. It’s also a security problem. Give your application only the permissions it needs.
Hardcoding credentials in source files
Once secrets are in code, they tend to spread. They get copied into examples, test files, and deployment scripts. Use environment variables and rotate credentials if you suspect they were exposed.
Ignoring connection pooling
Small apps can get away with a direct connection. As traffic grows, you may need pooling through PgBouncer or a managed equivalent. Without it, you can hit connection limits long before your server is actually busy.
Letting Claude Code generate schema changes without review
AI can draft the migration, but you should still check:
- Whether columns allow
NULLcorrectly - Whether indexes match real query patterns
- Whether foreign keys are appropriate
- Whether a migration might lock a large table for too long
Skipping backups because the project is “still early”
Early-stage apps are often the easiest to back up and the hardest to recover from if you haven’t set anything up. Make backups part of the initial deployment, not a later cleanup task.
A practical schema checklist for Claude Code projects
If you’re asking Claude Code to design tables, this checklist helps keep the output sane:
- Start with entities, not columns. Define the objects your app stores first.
- Normalize where it matters. Don’t duplicate user data across tables unless you have a reason.
- Add timestamps everywhere. Use
created_atandupdated_atconsistently. - Index query-heavy fields. Especially foreign keys, status columns, and lookup keys.
- Use constraints. Enforce uniqueness and required relationships in the database, not just the app layer.
- Prefer explicit naming. Tables like
user_profilesandinvoice_itemsare easier to maintain than generic names likedataorrecords.
If you want Claude Code to help design the schema, ask it to produce three things: the tables, the relationships, and the migration steps. That gives you a better review surface than asking for “the database code” and hoping it gets the structure right.
How to back up PostgreSQL safely
A good PostgreSQL setup is not just about creating tables. You also need a recovery plan.
For a first pass, use pg_dump for logical backups:
pg_dump "$DATABASE_URL" > backup.sql
For larger databases, compressed custom-format dumps are usually better:
pg_dump -Fc "$DATABASE_URL" -f backup.dump
Then automate the backup and store it somewhere separate from the server. A backup on the same disk as the database is not much help if the disk dies.
At minimum, verify that you can restore the backup:
pg_restore -d myapp_restored backup.dump
If you’re using a platform with built-in backups, like a managed Linux hosting setup, still test the restore process. Backups only count if they can be restored under pressure.
Local development versus production
It’s fine to start with SQLite or a local PostgreSQL instance during development, but production should match the same storage engine and as much of the same schema behavior as possible.
Here’s a simple rule:
- Development: quick setup, disposable data, frequent schema changes
- Staging: production-like config, seeded test data, realistic migrations
- Production: locked-down credentials, backups, monitoring, and restore tests
If Claude Code is building features in all three environments, keep the database URL and migrations consistent so you don’t discover differences only after deployment.
When to consider a managed database
Running PostgreSQL yourself is fine for many projects, especially if you want full control. But a managed database can be worth it when you need:
- Automated backups and point-in-time recovery
- Built-in high availability
- Easy scaling without managing the OS
- Less operational work for a small team
The tradeoff is cost and less control over the server environment. For developers who want to stay close to the Linux stack and keep the whole app in one place, self-hosting can still make sense. That’s especially true in a sandboxed setup where the app, agent, and database are easy to reason about together.
Quick setup checklist
Before you ship, verify these items:
- PostgreSQL is installed and running
- Your app has its own database and non-root user
- The database URL is stored as a secret or environment variable
- Migrations are versioned and tested
- Indexes exist for common queries
- Backups run automatically
- You’ve tested one restore
- Production credentials are different from development credentials
Final thoughts
Setting up PostgreSQL is one of those tasks that looks boring until it saves your project. If you’re building with Claude Code, taking the time to create a clean database setup will pay off every time you add a feature, change a schema, or recover from a bad deploy.
The basic formula is simple: use a dedicated database user, store credentials safely, wire up migrations, and make backups real instead of aspirational. If you keep those pieces in place, how to set up a PostgreSQL database for a Claude Code app becomes less of a one-time task and more of a repeatable part of your deployment process.
For teams building on Linux with an agent in the loop, that kind of discipline matters more than flashy tooling. It’s what keeps the app stable when the code changes fast.