Why my portfolio runs on Astro and SQLite instead of a CMS

No headless CMS, no external database, no monthly bill per seat. One Node process and one SQLite file run this whole site, admin panel included.

The site you’re reading has a full admin panel. I can write posts, add projects, upload images, read contact messages and approve reviews from my phone. There’s no CMS behind it, and no database server. It’s one Astro app and one SQLite file.

The options I didn’t pick

A static site generator with Markdown files is lovely until you want to fix a typo from your phone. A headless CMS solves that, but adds another account, another API, another bill and another thing that can go down. WordPress solves it too, and brings plugins, updates and a login page every bot on the internet already knows about.

I wanted the editing comfort of a CMS with the simplicity of a static site.

Astro in server mode

Astro is best known for static sites, but it also runs as a normal Node server. Pages are rendered on request, and they ship almost no JavaScript unless a component asks for it. The animations on this site are the only scripts that load, and the content is readable before they run.

Server mode means a new post is live the moment I hit publish. No rebuild, no waiting for a deploy.

SQLite is enough

SQLite gets underrated because it’s “just a file”. For a site with one writer and many readers, that’s exactly its strength:

  • Reads are very fast, because there’s no network hop to a database server.
  • A backup is a copy of one file. Mine runs every night.
  • There’s nothing to install, patch or keep running next to the app.

It would be the wrong choice for a site with many people writing at the same time. A portfolio is not that site.

Do the heavy work once, when saving

When I save a post, the Markdown is turned into HTML, code blocks are highlighted, the table of contents is built and the reading time is counted. All of that is stored in the database. When someone opens the page, the server just reads the finished HTML.

Share images work the same way. Every post and project gets an Open Graph image generated from its title the first time it’s requested, then cached on disk. I never design a thumbnail by hand, and every link shared on X or LinkedIn still gets a proper preview card.

SEO comes from the same data

Because everything lives in one place, the SEO files can’t drift out of date. The sitemap, the RSS feed and the structured data on every page are all built from the same tables the pages use. Publish a post, and it’s in the sitemap and the feed straight away, with the right dates.

The basics are boring, and they matter more than any trick: a real title and description on every page, one canonical address per page, fast loading on a phone, and headings that make sense when read on their own.

An admin panel worth trusting

A login page on a personal site is a target, so I treated it like one. Passwords are hashed with Argon2id. Two-factor sign-in is mandatory, not optional. Sign-in attempts are rate limited and admin actions go into an audit log. Uploaded images are re-encoded on the server, so a file pretending to be an image never gets served as one.

The trade-off

This site runs on one server. If that server is down, so is the site, and a static site on a global CDN would survive that better. For a portfolio, I’ll take that trade for the control and the zero monthly bill. The server setup has its own post.

If you’d like a site like this for your own business, fast, easy to edit, and without a monthly CMS fee, have a look at what I offer.

Written by Mohit Kamboj, a full-stack developer in Chandigarh, Punjab, India. Need something like this built? Tell me about it.