Hackathon Starter's seams: Sass runs before app.js, and eight OAuth buttons ship with no keys
A boilerplate for Node.js web applications
At a glance
- What is it?
- What the Node.js boilerplate actually does on install and on start, and what a team inherits when eight OAuth providers and twenty API examples all need credentials nobody has registered yet. Cheaper to read this before a weekend than at 2am during one.
- Who is it for?
- Take it when your weekend is going into product logic and you would rather not assemble sessions, a contact form, uploads, and OAuth by hand. Skip it when you need a narrow stack or a dependency tree that stays pinned.
- 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 2 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 1, 2026, and from our analysis. They are not legal advice.
Editorial analysis
npm start compiles Sass before app.js ever loads
The start script is two commands joined with `&&`:
"start": "npm run scss && node app.js"The right half of that expands to one long Sass invocation:
"scss": "sass --no-source-map --silence-deprecation=import --quiet-deps --load-path=./ --update ./public/css:./public/css"Because the halves are chained, the Node process begins only after Sass exits clean. One stylesheet error under the load path keeps the port closed and you read a Sass stack trace instead of a running app. The base URL in the environment template is `http://localhost:8080`, so 8080 is the port the rest of the stack expects. This compile is not a one-time install step either. It runs on every start and again from `postinstall`, so a style error surfaces twice per session. Flags like `--silence-deprecation=import`, `--quiet-deps`, and `--no-source-map` are set to keep that output readable, which also withholds the warnings that would explain a layout problem. `--update` writes compiled output back into `public/css`.
The install chain patches packages, builds CSS, and installs Husky
Dependencies are patched and styled before your first boot. The `postinstall` entry is `patch-package && npm run scss`, and the `patches/` directory at the repository root holds the patch files it applies. The `prepare` entry is:
"prepare": "node -e \"if(process.env.NODE_ENV!=='production'){require('child_process').execSync('husky',{stdio:'inherit'})}\""Read that guard. Husky installs unless `NODE_ENV` is exactly `production`, so if your shell, container image, or build server exports that value before `npm install`, the hook never lands and the `.husky/` directory already in the repo does nothing. Nothing in the application breaks, which is the problem. You lose the commit-time checks without a message telling you they are gone.
Formatting is wired the same way. The `lint` script runs `eslint "**/*.js" --fix && prettier . --write`, and `lint-check` runs both without the write flags, against `eslint.config.mjs`, `.prettierrc`, and `.prettierignore`. What the project cannot decide is which of these you keep. A team that clones and edits without ever running the lint script can carry formatting drift through every file it touches, and the drift shows up as noise in someone else's review.
clean-install deletes node_modules, the lockfile, and the coverage directory
The reset script is the one to read twice:
"clean-install": "node -e \"fs.rmSync('node_modules', { recursive: true, force: true }); fs.rmSync('package-lock.json', { force: true }); fs.rmSync('tmp', { recursive: true, force: true });\" && npm install"It removes three things, not one. `node_modules` goes, the whole dependency tree is resolved again from the version ranges in `package.json`, and `tmp` is deleted alongside it, which is where the coverage reporter writes its output. The repository does ship a tracked `package-lock.json`, so a pin does exist on disk. This script discards that pin on purpose and reinstalls against whatever the ranges resolve to that day. If you need the tree you actually tested, restore the tracked lockfile from git before running the install. Otherwise two teammates running this on the same commit can land on different transitive versions, and the diff that explains the difference is not in either working tree.
One .env.example holds a slot for every provider the feature list promises
The environment template is a flat file of placeholders. Core values sit at the top: `BASE_URL=http://localhost:8080`, `MONGODB_URI=mongodb://localhost:27017/test`, `SITE_CONTACT_EMAIL`, `TRANSACTION_EMAIL`, and `SESSION_SECRET=Your Session Secret goes here`, then `SMTP_USER`, `SMTP_PASSWORD`, and `SMTP_HOST` for the contact form. The comment at the top says these values are placeholders, that you need to register with the API providers your application needs, and that any of them can be overridden through environment variables such as `export SMTP_PASSWORD=blah_blah_blah`.
Below that sit the provider slots: `ALPHA_VANTAGE_KEY`, `DISCORD_CLIENT_ID`, `DISCORD_CLIENT_SECRET`, `FACEBOOK_ID`, `FACEBOOK_SECRET`, `FACEBOOK_PIXEL_ID`, `FOURSQUARE_APIKEY`, `GIPHY_API_KEY`, `GITHUB_ID`, `GITHUB_SECRET`, `GOOGLE_ANALYTICS_ID`, `GOOGLE_PROJECT_ID`, `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET`, `GOOGLE_API_KEY`, `GOOGLE_MAP_API_KEY`, `GOOGLE_RECAPTCHA_SITE_KEY`, `GROQ_API_KEY`, `GROQ_MODEL`, and `GROQ_VISION`. Three are empty on purpose, since the analytics, pixel, and reCAPTCHA entries are marked optional. The rest carry filler strings, and the Facebook and GitHub pairs carry long numeric and hex values that read like real credentials at a glance. They are not, and `SESSION_SECRET` is the literal sentence you are expected to replace.
Eight OAuth buttons and twenty API examples, all dead until keys arrive
The feature list is the draw, and it is also the cost. Eight OAuth 2.0 providers are wired: Google, Microsoft, Facebook, LinkedIn, X (Twitter), Twitch, GitHub, and Discord, alongside local email sign-in, passwordless, passkey, and two-factor options using email codes or an authenticator app. The API examples span backoffice integrations (Lob for USPS mail, Paypal, Quickbooks, Stripe, Twilio for text messaging), data and media (Alpha Vantage with ChartJS, Github, Foursquare, Last.fm, New York Times, PubChem, Twitch, Tumblr as an OAuth 1.0a example, Steam via OpenID, web scraping, GIPHY), maps (Google Maps, HERE Maps), and productivity (Google Drive, Google Sheets). The AI section adds a ReAct agent with tool calling and MongoDB session persistence, retrieval with embedding caching, text and image models, and providers reached through LangChain, Groq, and Hugging Face.
None of it runs on a fresh clone. There is no switch that enables a group of them, and each provider needs its own application registration, its own key pair, and a redirect URI matching your `BASE_URL` before one sign-in completes. The consequence for a hackathon team is a codebase where most buttons are dead code until somebody with an account at that provider registers an application, and nothing in the environment template automates that step.
npm test excludes the link suite, and the browser runs download their own Chromium
The default test command deliberately skips part of the suite:
"test": "c8 --temp-directory=tmp/coverage --reporter=html --reporter=text --reports-dir=tmp/coverage mocha --timeout=60000 --exit --exclude \"test/*links.test.js\""The `--exclude` drops the link file, which is checked by a separate command with a much longer timeout:
"test:image-link": "mocha --timeout 300000 \"test/*links.test.js\""So a green `npm test` says nothing about whether the demo's external URLs still resolve, and the omission reads like ordinary coverage rather than a deliberate split. Coverage itself lands in `tmp/coverage` as both HTML and text reports, and `--exit` ends the process instead of waiting for open handles to drain. Browser tests come in three configurations, chromium for live runs, chromium-replay, and a custom project, and each one carries a pre-step that fetches the browser binary first:
"pretest:e2e:live": "npx playwright install chromium"The practical limit is on verifying anything that touches a live OAuth callback: you pay a Chromium download before the run starts.
Node.js LTS 24, a MongoDB you supply, and a Nodemon install that lives outside the repo
Three things must exist before the start script can do anything. MongoDB runs locally or through a hosted instance, and Node.js is pinned to the latest LTS, named as LTS 24. Command line tools are listed per platform, and those commands are the part that actually differs:
xcode-select --install
sudo apt-get install build-essential
sudo dnf groupinstall "Development Tools"
sudo zypper install --type pattern devel_basisThen four commands produce a running app:
git clone https://github.com/sahat/hackathon-starter.git myproject
cd myproject
npm install
npm startThe gap in that path is the restart loop. The setup notes call for Nodemon, suggest installing it with `sudo npm install -g nodemon`, and say to run `nodemon app.js` instead of `node app.js` because it saves restarting the server after every small change. That is a global install rather than a dependency, so it is invisible to `package.json` and absent from any machine that did not run it. What the project cannot do is hand a teammate the same editing loop through the repository itself.
Version 10.0.0 is current, and the changelog is the only upgrade path
The version field in `package.json` is 10.0.0, and it sits on a long line of majors: 8.1.0 on 2025-02-01, 9.0.0 on 2025-04-12, and 10.0.0 on 2026-02-09, with pushes landing on the master branch as recently as 2026-09-25. The repository is neither archived nor dormant.
The catch is that a major number in this project moves the ground under you. The feature list has grown across majors, from plain local sign-in to passkeys, two-factor, linked provider accounts, token revocation, contact form, file upload, device camera, and the AI agent examples, so code written against an older major can assume a template that no longer exists. The project's answer to that sits in a changelog file at the repository root, linked from the top of the README as the place to see what changed. That file and the version field are what to read before a team commits to the boilerplate, and the version field again before every merge.
Editorial conclusion
Take it when your weekend is going into product logic and you would rather not assemble sessions, a contact form, uploads, and OAuth by hand. Skip it when you need a narrow stack or a dependency tree that stays pinned. Before committing, check the version field against your Node.js LTS 24 setup, read the changelog at the repository root for the jump between majors, and decide which providers you will actually register, because every unconfigured button is dead code in your repo. The author also suggests using it as a learning guide if all you want is one Google sign-in.
Frequently asked questions
What is a hackathon for beginners using Hackathon Starter?
The setup narrative names the time cost directly: you have to decide what to build, pick a language, pick a web framework, and pick a CSS framework before anyone can contribute. Hackathon Starter bundles that choice into a Node.js MVC app with Bootstrap 5.3 and Sass already wired in.
What beginner hackathon ideas does Hackathon Starter ship examples for?
Sign-in is the smallest one on offer, with Sign in with Facebook named as the example that can cost hours if OAuth 2.0 is unfamiliar. Other included pieces are a contact form over SMTP, file upload, device camera, flash notifications, and a dark mode toggle that defaults to OS preference.
What are the best beginner hackathons according to Hackathon Starter?
The repository names no specific hackathons or events anywhere in its setup pages. It carries Product Hunt testimonials instead, including one reader who said a team used the boilerplate for a weekend hackathon and won prizes with it.
How do I start a hackathon with Hackathon Starter?
You need MongoDB plus Node.js LTS 24 and the platform command line tools, then four commands: clone, change directory, npm install, npm start. The AI examples and API integrations only come online after you fill the matching keys in the environment template.
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/sahat-hackathon-starter)