SaaS Boilerpate: a Flask and React starting point with authentication already wired
Free SaaS boilerplate (Python/PostgreSQL/ReactJS/Webpack)
At a glance
- What is it?
- This free boilerplate assembles a working SaaS web application from a Flask backend, PostgreSQL, a React single page frontend and Webpack. It ships email authentication with confirmation, JWT sessions held in cookies, a profile endpoint, error pages, a component library and a JSON-driven dashboard whose menus generate their own routes.
- Who is it for?
- Adopt this boilerplate if you want a runnable multi-user application with authentication and a dashboard shell today, and you are content to work within Flask, React and the versions the project pins. Do not adopt it as a starting point for a long-lived product without modernising the dependency set, because the pins are several years old.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 107 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 25, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the boilerplate gives you
The repository description calls it a free SaaS boilerplate, and the README says the free boilerplate allows creating a working SaaS web application. The technologies are listed plainly: Python with Flask on the back end, PostgreSQL for the database, ReactJS on the front end, CSS and SCSS for styling, FontAwesome for icons, and Webpack with Babel for the front end build.
The features section starts with user authentication: email authentication with email confirmation, user registration, login and logout, and a simple user profile page. The interface section is left as a heading with nothing under it in the visible text, which is a small indication that the documentation is uneven.
The system requirements line is the one that tells you the vintage: currently, the boilerplate works with Python 3.5.
That single fact frames everything else in this repository. The dependency pins in requirements.txt and package.json are correspondingly old, and the README asks you to file information about the project on the vendor's website at saasforge.dev, which suggests a commercial offering sits alongside the free template.
The licence is MIT, the default branch is master, and the last push was on 2026-07-11 with no GitHub releases. The repository name and the repository slug differ, the slug carrying a typo, which suggests the project was renamed at some point without updating the identifier.
How the project is organised: blueprints, modules and components
The project structure section explains the organising principle, and it is a good one for a template because it shows where to put your code.
Everything is put into separate structures, often with the front end and back end side by side, and the project is divided into parts.
Blueprints are the back-end applications. They are based on Flask blueprints, which allows separating parts of an application that are significantly different from each other and require a different level of authentication or authorisation. There are three: Authentication, which contains the root HTML file and links to the authentication React component; Dashboard, whose root HTML links to the dashboard view; and an Errors page, which is explicitly not a blueprint, just a simple HTML page for serving back-end errors.
Modules are the code that cannot be decoupled and should go together, front end and back end, because they belong to the same functionality and the front end often calls endpoints from the same module's back end. Two conveniences are documented: the API endpoints are imported and registered in the dashboard blueprint automatically, and if the back end needs to initialise an extension using init_api(), that function should be provided in the .py code and it will be called automatically.
That second mechanism is the one to understand. A module declares an init_api() function and the boilerplate calls it during registration, so a module can set up its own routes and hooks without the dashboard blueprint having to know the module exists.
Components are React pieces of code, sometimes with CSS, and they have no back-end part. The README notes that this is only a description of the components, and that all the documentation for each one can be found in its folder. The components are listed in alphabetical order, and the visible ones are Alert, Dropdown menu and Left menu, plus the module-level ones: Auth, ComponentsDemo, ErrorPages and Profile.
Authentication: JWT in cookies and four server-side functions
The Auth module is the part of a boilerplate worth reading carefully, because authentication is the part most likely to be wrong in a from-scratch implementation.
The server side holds the API and the registration and email confirmation logic, and the authentication is implemented using JWT with Flask-JWT-Extended and PyJWT in the dependency list. The choice of storage is stated and justified: the implementation uses cookie-based tokens as it is the most safe method of using tokens at the moment.
The server-side API has exactly four functions. init_app initialises the JWT-Flask manager and adds the needed configuration variables to the application. login_create_tokens creates a token on the user's login and attaches the corresponding cookies to the response object. logout unsets the cookies from the response on the user's logout. And token_refresh updates the access token on demand.
Four functions covering the whole token lifecycle is a compact surface, and the refresh function in particular is the one that decides whether a user gets logged out mid-session.
The front end of the Auth module is a React component with routes working as a single page application, with a responsive design, and the pages are register, login, a finish registration info page, and a confirmation page with automatic redirection to the login page. The README includes screenshots of the registration page on a normal screen and on a mobile screen, and of the confirmation page on a mobile screen.
Separately, the front end functions file is referred to in the Auth jsx component, and its only purpose is to add an interceptor to all the requests made by axios. You do not need to call it directly.
That detail is the interesting one. Rather than having each component attach a token to its requests, one axios interceptor adds it to all of them. It is a small decision that removes a class of bug where one endpoint forgets the header.
JSON-driven menus that generate their own routes
The dashboard navigation is the part of the boilerplate that shows the most design ambition, and it is worth understanding because it is the pattern that saves the most work as a project grows.
The top menu is defined as a plain JSON array of objects, each with a title, a url, a component, and optionally a divider, a method and a redirectUrl:
const topMenu = [
{title: 'Profile', url: '/app/profile', component: lazy(() => import('@src/modules/profile/ProfileView'))},
{title: 'Change password', url: '/app/password', component: lazy(() => import('@src/modules/password/ChangePasswordUI'))},
{divider: true},
{title: 'Logout', url: '/api/auth/logout', method: 'post', redirectUrl: '/auth/login'}
];The left menu is the same idea with grouping, a group title and a list of items each carrying an icon, a colour, a url and a lazily imported component.
The features list for the dropdown makes the payoff explicit. You specify data in the human-friendly JSON data structure. You can specify a divider. You can specify a method if it is not POST. You can specify a redirectURL if you do not need to load any component but rather redirect the user to another page. And you do not need to import components anywhere else, because all routes are generated automatically.
The lazy import syntax is what makes the automatic routing possible without a build-time route table. Each entry names its component through a dynamic import, so the bundler produces a separate chunk for it and the router discovers it from the menu definition itself.
The left menu adds responsive behaviour: a responsive, collapsible menu with any amount of items on each level, created by filling up the JSON data file, with screenshots of the expanded and collapsed states and of the small screen layout. If you prefer, you can import the component separately and assign it explicitly in the menu data structure, which is the escape hatch for the cases the automatic approach does not cover.
Running it: Docker, Compose and the Heroku path
The deployment files are conventional and the README does not add much narrative to them, so the files themselves are the documentation.
The Dockerfile starts from python:3.5-alpine, installs the build tools including gcc, musl-dev, npm, postgresql-dev and python3-dev, copies the requirements and installs them, then installs the Node dependencies and runs the development build before setting the entrypoint to the shell script.
The compose file runs a PostgreSQL 12.0 alpine service with a named volume for the data, and an app service built from that Dockerfile with a dependency on the database. The app gets its Flask configuration from the environment with defaults for the app name, the environment, the run host and the two secrets, and a database URL pointing at the db service. Port 5000 is published and the working directory is mounted into the container.
The two secret variables are the notable detail. jwt_secret_key defaults to FAKE_JWT_SECRET_KEY and secret_key to FAKE_SECRET_KEY, which is the right way to ship a template: the placeholder is obviously a placeholder, and a deployment that forgets to set them is visibly broken rather than subtly insecure.
The PostgreSQL password in the compose file is literally password and the database is dev, which is fine for a template and must not survive into a deployment.
There is also a Procfile, which is the Heroku convention, and the package.json carries heroku-prebuild and heroku-postbuild scripts that run npm install and then the webpack build for the target environment. So the project supports both a container deployment and a Heroku one, with init.sh and init.bat for local setup and entrypoint.sh for the container.
On the front end, the package.json scripts are dev and prod, each running webpack with the matching configuration file, and the repository has webpack.common.js alongside webpack.dev.js and webpack.prod.js with webpack-merge to combine them.
Limits: an old dependency set and a template's nature
The limits are visible in the pins.
The first is Python 3.5, which the README states as the working version, and the requirements.txt that follows from it. Flask is pinned at 1.0.2, SQLAlchemy at 1.3.10, Werkzeug at 0.16.0, PyJWT at 1.7.1 and Jinja2 at 2.10.3. These are versions from 2019, and several of them, Flask and Werkzeug among them, have had security advisories since.
The front end pins are the same vintage. React 16.13.1, webpack 4.44.1, axios 0.19.2, Bootstrap 4.5.2, node-sass 4.14.1, jQuery 3.5.1 and MobX 5.15.5. node-sass in particular is a package that has to compile native bindings against the Node version in use, which makes the modern Node requirement awkward.
The second is the nature of a template. The boilerplate gives you authentication, a profile, error pages, a component library and menu-driven routing. It does not give you billing, multi-tenancy, roles beyond the authentication split, email sending beyond the confirmation, or a job queue. The visible component list ends at Alert, Dropdown and Left menu, and the visible modules end at Profile. The README's own Interface section is an empty heading, which suggests the visible documentation is incomplete rather than the project being small.
The third is the error handling, which the README scopes explicitly. Currently only one error, a 404 file not found, is handled, with a screenshot of the 404 dashboard page. An unhandled server error is not in the visible scope.
The fourth is the absence of tests. The package.json test script is the default placeholder that echoes an error and exits 1, and the requirements.txt contains no test framework. A template with no tests is normal, since the template is scaffolding rather than a tested product, but it means you are inheriting code that has never been automatically verified.
This boilerplate against a modern framework and against a full SaaS starter kit
Two comparisons make the choice clearer.
The first is against starting a new project with a current framework. A modern Python stack would give you a supported Flask or a different framework, current SQLAlchemy, current Werkzeug and current cryptography libraries, and a Node toolchain you can still install without pinning to a version that has to compile native bindings. The difference in approach is that this template gives you a specific, working shape immediately, with the pieces a SaaS product always needs already connected, and it gives you that shape with the versions it was written against.
If you are comfortable assembling those pieces, the sensible route is to take the menu-driven routing idea, which is genuinely good, and implement it on current versions. The authentication flow, the module registration hook and the axios interceptor are the parts worth carrying over.
The second comparison is against a commercial or larger open source SaaS starter kit. Those come with billing integration, role-based access control, admin tooling, background jobs, testing and CI configuration, and they come with a licence and a support model. The difference in approach is that this template is a skeleton you fill in, while a fuller kit is a product you configure and then fight when it does not fit.
The template is smaller and more permissive, and it is genuinely MIT licensed with no strings attached. For a developer who wants to see how a working multi-user application is put together, or who wants a starting point they can reshape entirely, that is worth having. For a team shipping to customers this year, the outdated pins are the thing that decides it.
Editorial conclusion
Adopt this boilerplate if you want a runnable multi-user application with authentication and a dashboard shell today, and you are content to work within Flask, React and the versions the project pins. Do not adopt it as a starting point for a long-lived product without modernising the dependency set, because the pins are several years old. Verify first that Python 3.5 and the pinned package versions are acceptable in your environment, that you replace the placeholder secrets and database password before any deployment, and that the Heroku and Docker paths both work for where you intend to run it.
Frequently asked questions
What stack does the SaaS boilerplate use?
Python with Flask on the back end, PostgreSQL for the database, ReactJS on the front end, CSS and SCSS for styling, FontAwesome for icons, and Webpack with Babel for the front end build. The README states that the boilerplate currently works with Python 3.5, and the repository ships a Dockerfile, a docker-compose file and a Procfile.
How does the boilerplate handle authentication?
The Auth module implements email authentication with confirmation using JWT, with the token held in a cookie because the README describes that as the most safe method of using tokens at the moment. The server-side API has four functions: init_app to initialise the JWT manager and configuration, login_create_tokens to create a token and attach the cookies, logout to unset the cookies, and token_refresh to update the access token on demand.
How do the dashboard menus work?
Both the top menu and the left menu are defined as JSON data. Each entry carries a title, a url and a lazily imported component, and can also specify a divider, an HTTP method and a redirect URL. Because routes are generated from the menu definition, components do not need to be imported anywhere else. The left menu adds responsive collapsible behaviour with any number of items per level, and the README notes you can import a component separately and assign it explicitly if you prefer.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/saasforge-open-source-saas-boilerpate)Was this useful?