A Production-Readiness Checklist for Student Full-Stack Projects
You have been working on a full-stack project for weeks or months. It runs on your machine. The features work. The demo went well. Now you want to deploy it so other people can use it.
This is the moment where most student projects stall. The gap between "works on my laptop" and "works reliably on a server" is filled with problems that tutorials do not cover: secrets in the codebase, missing error handling, no backups, and the database that disappears when the container restarts.
This checklist is the result of deploying several of my own projects and learning these lessons the hard way. Not every item applies to every project. Adapt the level of complexity to what you are building.
Environment Variables and Secrets
- No API keys, passwords, or tokens in the source code
- No
.envfiles committed to git (check.gitignore) - All secrets passed through environment variables
- A
.env.examplefile documents the required variables (without real values) - No hardcoded database URLs, JWT secrets, or third-party API keys
- Demo/test credentials clearly marked and excluded from production
Database
- Migrations run automatically before the application starts
- Seed scripts are idempotent (safe to run multiple times)
- Seed scripts do not overwrite manual changes
- Database data persists across container rebuilds (volume mounted)
- Backup strategy exists and has been tested
- Restore from backup has been tested at least once
- No
DROP TABLEorDELETE FROMin seed scripts
Authentication and Authorization
- Passwords are hashed (bcrypt, argon2, or scrypt -- not MD5 or SHA1)
- Sessions or tokens expire after a reasonable duration
- Refresh tokens can be revoked
- Login attempts are rate-limited (brute force protection)
- Admin routes require authentication
- Role-based access control works correctly (operators cannot access admin functions)
- HTTP-only cookies for sensitive tokens (not localStorage)
Input Validation and Security
- Server-side validation on all user inputs
- Client-side validation for user experience (not as a security measure)
- SQL injection prevention (use parameterized queries or an ORM)
- XSS prevention (escape output, sanitize HTML)
- CORS configured correctly (not
*in production) - CSRF protection for form submissions (where applicable)
- File upload validation (type, size, and content inspection)
Error Handling
- Unhandled exceptions do not expose stack traces to users
- Custom error pages exist (404, 500)
- Errors are logged with enough context to debug
- Sensitive information is not included in error messages
- The application does not crash on invalid input
Testing
- Core business logic has unit tests
- API endpoints have integration tests
- Critical user flows have end-to-end tests (if applicable)
- Tests run in CI (not just locally)
- Test coverage is reasonable (not 100%, but covering the important paths)
- Tests pass before deployment
Lint, Typecheck, Build
- Linter runs without errors or warnings
- Type checker passes (TypeScript
--noEmit, Python mypy, etc.) - Production build succeeds
- Build output is tested (not just the dev server)
- Build artifacts are not committed to git
Docker
- Dockerfile uses multi-stage builds (small final image)
- Application runs as a non-root user inside the container
- Health check is defined (or at least a startup log message)
- Container restarts automatically (
restart: unless-stopped) - Environment variables are documented
- Volumes are mounted for persistent data
- Logs are written to stdout/stderr (not to files inside the container)
Deployment
- The application is accessible from outside localhost
- HTTPS is configured (or a reverse proxy handles it)
- Domain name resolves correctly (if applicable)
- Port configuration is flexible (not hardcoded to 3000)
- The deployment process is documented (even if just a few commands)
- Rollback procedure exists (how to revert to the previous version)
Performance and Reliability
- Images are optimized (not serving 5MB PNGs for thumbnails)
- Database queries use indexes for frequently accessed fields
- API responses are reasonably fast (under 500ms for simple queries)
- No memory leaks in long-running processes
- Static assets are served efficiently (CDN, caching headers)
Accessibility and Responsiveness
- The application works on mobile screens
- Forms are usable with keyboard navigation
- Color contrast meets WCAG guidelines (at minimum AA level)
- Images have alt text
- Focus indicators are visible
SEO (for public pages)
- Pages have meaningful title tags
- Meta descriptions exist for important pages
- A sitemap is generated (if applicable)
- Robots.txt is configured
- Structured data is included (if applicable)
- URLs are descriptive (not just numeric IDs)
Monitoring and Logging
- Application logs are accessible (stdout, log files, or a logging service)
- Error rates are visible (even if just manual checks)
- Database connection failures produce clear log messages
- Startup logs confirm successful initialization
- Failed login attempts are logged
Documentation
- README explains what the project does and how to run it
- Required environment variables are listed
- The tech stack is documented
- Deployment instructions exist (even if brief)
- Known limitations are acknowledged
The "Good Enough" Principle
Not every project needs every item on this checklist. A personal portfolio does not need comprehensive monitoring. A hackathon prototype does not need end-to-end tests. A demo application does not need automated backups.
The question is not "did I check every box?" but "do I understand the risks I am accepting by skipping certain items?"
If you deploy without backups, know that you might lose data. If you skip tests, know that regressions will reach production. If you hardcode secrets, know that they might end up in your git history.
The projects I am most proud of are not the ones with the most features. They are the ones where I understood every layer, from the database schema to the Docker entrypoint to the HTTPS certificate. That understanding is what separates a working demo from a deployable application.