HIMANSHU BANSAL
Back to Blog
Full Stack Development8 min read

What I Learned Deploying a Full-Stack URL Shortener

A practical breakdown of building and deploying a URL shortener with .NET 8, PostgreSQL, JWT authentication, React, Render, and Vercel.

.NET 8ReactPostgreSQLDeploymentJWT

Intro

The URL shortener was one of the most useful full-stack projects I built because it looked simple at first and then quickly became real. Creating a short link is not difficult by itself. The interesting part starts when users need accounts, custom aliases, expiry support, analytics, QR codes, ownership rules, and deployment.

This project helped me practice the full path from backend API design to frontend integration and production deployment. It also reminded me that local success does not guarantee production success.

Why I worked on this

I wanted a project that was small enough to complete but serious enough to include real backend concerns. A URL shortener is a good fit for that because the core idea is easy to understand, but the implementation still requires careful decisions.

I also wanted hands-on practice with a modern stack: .NET 8 Web API, PostgreSQL, Entity Framework Core, JWT authentication, React, Tailwind CSS, Render, and Vercel.

What problem I was trying to solve

The product problem was to let users create and manage short links. The backend problem was to make that safe and predictable.

A real URL shortener has to handle:

  • user authentication with JWT
  • short-code generation and uniqueness
  • custom aliases
  • expiry dates
  • redirect flow
  • click analytics
  • user-owned URLs
  • API rate limiting
  • logging and production configuration

If these rules are not handled carefully, users can collide on aliases, access links they do not own, or create links that behave differently in production than they did locally.

How I approached it

I treated the backend as the source of truth. The React frontend is responsible for the user experience, but ownership, validation, expiry checks, alias uniqueness, and redirects belong on the server.

The redirect flow is the most important part. A request comes in with a short code. The API looks up the matching URL, checks whether it exists, verifies that it has not expired, records analytics, and then redirects to the original destination.

For authenticated dashboard actions, JWT protects the user routes. PostgreSQL stores users, URLs, aliases, expiry metadata, and click events. Entity Framework Core handles database access, while constraints help protect the data model.

Deployment added another layer. The backend and frontend were deployed separately, so CORS, environment variables, API base URLs, JWT settings, database connection strings, logging, and production configs all had to line up.

What I learned technically

I learned that a small app still needs clear boundaries. Redirect logic should be narrow and fast. Dashboard logic should care about ownership and management. Analytics should not make redirects fragile.

I also learned how much deployment changes the way you think. Locally, it is easy to assume everything is connected. In production, the frontend, backend, database, and environment variables all need to agree.

Render and Vercel made deployment approachable, but they also forced me to understand configuration more clearly. That was a good thing.

Another useful lesson was that logs and rate limiting are not optional extras. When an app is deployed publicly, I need some way to understand what happened when a request fails, and I need basic protection so the API is not completely open to abuse. Even simple structured logs make debugging less stressful.

The project also made frontend and backend contracts more important. The frontend should not guess how errors work. The API needs predictable responses so the dashboard can show useful messages instead of generic failure states.

Mistakes or confusing parts

One confusing part was deciding how much work should happen during a redirect. Recording analytics is useful, but redirects should stay quick. That is an area where Redis caching and better background processing could help later.

Another mistake was underestimating CORS and environment configuration. The code can be correct, but if production URLs or allowed origins are wrong, the app still fails.

What I would improve next

I would improve the Redis caching strategy for high-traffic short-code lookups, improve analytics with charts and filters, and add more automated tests around alias uniqueness, expiry, ownership, and redirects.

I would also improve CI/CD so build and deployment checks are more repeatable. The project is live, but there is still room to make it more production-minded.

Final takeaway

A URL shortener is not just a beginner CRUD project when it is built end to end. Authentication, redirects, analytics, ownership, deployment, and production configuration make it a practical full-stack learning project.