coffeechronicle.aniruddhagawali.dev
The traditional architectural blueprint for web applications almost always follows a three-tier structure: Frontend, Backend API, and Database. However, for my project, Coffee Chronicle, I decided to challenge this norm. The goal was to build a fully functional blog platform using only Next.js for the frontend and PostgreSQL as the core engine, effectively eliminating the need for a separate, traditional backend server.
The Idea: Why Go "Backend-less"?
The inspiration for Coffee Chronicle came from a desire to see how much logic a modern database could truly handle. Usually, the database is treated as a passive storage bin, while the backend handles the "heavy lifting" of authentication, validation, and business logic. I wanted to flip that script.
It is important to note: This architecture is an experimental learning project. While it is a powerful way to understand database internals, it is not necessarily recommended for large-scale production environments where specialized backend services provide better observability and middleware flexibility. This journey was about pushing the limits of PostgreSQL and mastering the art of database-driven development.
Why PostgreSQL?
Choosing PostgreSQL wasn’t just about reliability; it was about the unique features that other databases often lack. PostgreSQL is essentially a programmable environment. I relied heavily on:
- PL/pgSQL: This allowed me to write complex procedural logic directly in the database.
- Native JSON Support: Perfect for handling the dynamic content generated by modern rich-text editors.
- Advanced Extension Ecosystem: Which makes it possible to handle everything from cryptography to specialized data types.
Connecting the Frontend Directly to the DB
In Coffee Chronicle, the "Backend" isn't a Node.js or Python service; it’s a collection of Stored Procedures and Functions inside PostgreSQL. The Next.js frontend interacts with these functions via Server Actions.
Instead of writing SELECT or INSERT statements in the application code, the frontend calls a function like select create_blog(...). This keeps the schema logic encapsulated within the database itself. This approach drastically reduced the "glue code" often required to map API endpoints to database queries.
Authentication Inside the Database
One of the most challenging parts was moving the entire authentication flow into PostgreSQL. I didn't use an external provider like Firebase or Auth0. Instead:
- User Registration: A stored procedure handles the insertion of credentials.
- JWT Management: Using PostgreSQL extensions, the database itself generates and verifies JSON Web Tokens (JWT). When a user logs in, the DB validates the credentials and returns a signed token.
- Session Integrity: The database ensures that only valid, non-expired tokens are accepted for any data-modifying operation.
Security through Row Level Security (RLS)
Without a traditional backend to filter data, security must happen at the row level. This is where Row Level Security (RLS) and Policies became the backbone of the application.
I implemented RLS policies to ensure that:
- Public Access: Anyone can read published blogs.
-
Private Ownership: Only the author of a blog post can edit or delete it. This is enforced by a policy like
USING (auth.uid() = author_id), where the database identifies the user directly from the JWT provided in the session. - Isolation: One user cannot accidentally (or intentionally) access the draft content of another user, even if they know the specific blog ID.
Challenges and Lessons Learned
Creating a backend-less app isn't without its hurdles. The biggest issue I faced was Security and Debugging. When logic lives in the database, you lose some of the easy-to-read stack traces you get in a traditional backend. I had to become very disciplined with SQL error handling and logging.
I also had to carefully manage JWT secrets and ensure they were securely accessible to the database for signing. Another major learning point was the importance of Input Validation. Since the DB is the final gatekeeper, every function had to be meticulously written to prevent SQL injection and ensure data integrity.
Final Thoughts
Building Coffee Chronicle taught me that PostgreSQL is far more than just a place to store tables; it is a sophisticated runtime environment. While I might return to traditional backends for complex production systems, I now have a much deeper appreciation for the power of the database. If you want to truly understand how data, security, and identity intertwine, I highly recommend trying to "delete your backend" and letting your database do the talking.
Top comments (0)