The backend, explained

What is a backend, actually?

Every blog post, event, and form submission has to live somewhere. Here's what actually goes into storing it properly, and the fast way to skip all of it.

01

What a backend actually does

The part of a website nobody sees, and the part that actually remembers things.

The frontend is the part you can point at: the homepage, the colors, the layout. A backend is everything behind it that a page can't do on its own — a place to durably store information, and the logic that reads and writes it safely. Two pieces, always: a data store and the code that talks to it.

Anything on a site that has to be remembered needs both. A blog post has to still be there tomorrow. An event needs a real, growing list of who registered. A contact form has to land somewhere a human will actually see it. None of that happens by accident — something has to store it, and something has to fetch it back out correctly, every time.

02

What Gravity gives you today: JSON files

Real storage, not a demo — and exactly the right amount of it to start.

Out of the box, Gravity stores everything — blog posts, events, form submissions, portal accounts — as plain JSON files under data/content/. One file per record. No database to install, nothing running in the cloud, nothing to configure. This genuinely works. Plenty of small sites never need anything else.

It also has real limits, and they show up in a predictable order as a site grows:

  • It's not queryable. “Posts published last month, tagged X” means loading and filtering every file in Python — fine at 50 posts, slow at 5,000.
  • It's not concurrency-safe. Two people saving at once can race and silently overwrite each other. There's no transaction to make “read, change, save” atomic.
  • It's not relational. An event and its 200 registrants are two files that happen to reference each other by an ID — nothing enforces that link or cleans it up.
  • It's not always even persistent. Stateless hosts wipe local disk on every deploy — you already need a GCS bucket or Vercel Blob store just to survive redeploys.
03

So you add a database. Now what?

This is where “just use a real database” turns into its own project.

SQL isn't a database — it's the language you use to talk to one. A SQL database (Postgres, MySQL, SQLite) is software that stores rows in tables and enforces rules about them: a registrant has to reference a real event, two writes to the same row can't corrupt each other, a query across ten thousand rows comes back in milliseconds instead of a Python loop. That layer — SQL, sitting between your application and the actual stored bytes — is what JSON files don't have.

Postgres

The default choice for most new projects. Powerful, free, and the deepest ecosystem — also the most to learn.

MySQL

Older, still everywhere, slightly different tradeoffs. A safe, well-documented alternative to Postgres.

SQLite

One file, zero setup — great for a prototype. Risky once real concurrent traffic starts writing to it.

Whichever one you pick, it has to run somewhere: a managed service you now pay for and depend on, or a server you patch, back up, and keep awake yourself. Either way, that's infrastructure you own now, not a file that just sits in your repo.

04

Migrations: the part nobody warns you about

Your schema will change. Every environment has to change with it, in the same order, without losing data.

01

Your schema changes constantly

You'll add a status column to events, a phone field to contacts, a whole new table for something you didn't plan for on day one. In production, you can't just hand-edit the database — your laptop, staging, and production all need the exact same schema, applied in the exact same order.

02

A migration is a versioned, revertible script

A migration tool tracks every schema change as its own small script — add this column, backfill this default, drop that old table — that can be applied or rolled back on demand, and run in the same order everywhere.

03
alembic revision --autogenerate -m "add status to events"

In Flask, that's SQLAlchemy + Alembic

The standard pairing in the Python world: SQLAlchemy defines your tables as Python classes, and Alembic generates and runs the migration scripts that keep the real database's columns in sync with them — on your machine, in CI, and in production, every single time.

05

Everything you'd now own

None of this is impossible. It's just real, ongoing engineering work — not a weekend project.

The tally
choose + hosta database engine, and something to run it on
designa schema for every content type: blog, events, forms, contacts
write + reviewa migration for every schema change, forever
secureparameterized queries, credentials, network access
operatebackups, point-in-time recovery, uptime, connection limits
repeatthis modeling work for every new feature you add

Or connect Adhara, and skip all of it.

Adhara is EIM's managed backend: the database, the schema, the migrations, and the API layer for blog, events, forms, CRM, and commerce — already built, already hosted, already maintained. Gravity already knows how to talk to it.

Minutes, not weeks

No schema to design, no Alembic to learn, no server to patch. Set three environment variables and Gravity switches from local JSON to a real backend — the same way it already works today.

Already secure, already backed up

Parameterized queries, access control, backups, and uptime are Adhara's job, not yours. The engineering work in the section above is exactly what you're paying to not do.