App Get Is Not A Function | Fast Fix For Common Causes

The app get is not a function error means your app variable isn’t an Express app instance, so route methods like get() don’t exist.

This error shows up when you expect app to be an Express application, but it’s actually something else, like a plain object, a function, a Router, a promise, or an empty export. Once that happens, calling app.get() throws a TypeError and your server stops booting.

The fix is almost always a chain of checks. You confirm what app is, trace where it came from, then correct one file. That file creates the Express instance or exports it.

What App Get Means In Node And Express Code

In Express, app is the value returned by calling express(). That object has HTTP method helpers like get(), post(), and use(). Those helpers register route handlers and middleware.

If you never created the app with express(), or you replaced the variable later, then app won’t have those methods. The error message is blunt, but it’s also a clue. It’s not complaining about your route path. It’s complaining about the thing you’re calling.

If you want a fast sanity check, log the type right before the failing line. When you see anything other than “function” methods on an Express app, you’ve found the direction to take next.

  • Log The Value — Add console.log(app) once, right above the first app.get() call.
  • Log The Properties — Run console.log(Object.getOwnPropertyNames(app || {})) to see what you actually imported.

Run one test. Print typeof app, then check for listen and use. An Express app has both. A Router lacks listen, and a plain object lacks them all too in most setups today.

If those logs show an empty object, a Router, or something unexpected, jump to the section that matches your setup. The table below can narrow it in seconds.

App Get Is Not A Function In Express Apps With Common Causes

Most cases fall into a small set of patterns. The theme is the same each time. The file that calls app.get() is not holding the Express app you think it is.

What You See Likely Reason Fix To Try
app is { } Wrong export or import path Export the Express instance, then import it without destructuring
app is a Router You imported a router module Use router.get() inside the router file, then mount it with app.use()
Error starts after refactor Circular require between files Break the loop by injecting app into the module, or move routes into a router
Works in one file, fails in another Variable shadowing or reassignment Rename local variables and stop reusing app for other values
ESM import looks right, still fails Mixing CommonJS and ESM exports Match export default with import app from, or match module.exports with require()

Quick Checks That Solve Most Cases

Start with the basics. These catch the slip-ups that sneak in during copy-paste or a rushed refactor.

Make Sure You Created The Express App

Look for the line that creates the application. In CommonJS, it should look like const app = express(). In ESM, it will still call express(), but the import line changes.

  • Check The Create Line — Confirm you have const app = express() in the file that owns your server setup.
  • Check The Require Line — Confirm const express = require('express') (or an ESM import) points to the package, not a local file named express.
  • Check The App Variable — Confirm nothing reassigns app after creation.

Confirm You Didn’t Destructure The Wrong Thing

A classic bug is importing with braces when the module exported a default value, or importing a default value when the module exported named values. The result is often an empty object or the wrong property.

  • Match Default Export — If the app file uses module.exports = app, import with const app = require('./app').
  • Match Named Export — If the app file exports { app }, import with const { app } = require('./app').
  • Print The Import — Log the imported value right after the import line to confirm it’s the Express app.

Check That You Didn’t Import A Promise

Some setups build the app after async work, like reading config or connecting to a database. If you export the pending promise and import it as app, you’ll end up calling get() on a promise object.

  • Search For Async Exports — Look for async function createApp() patterns in your app module.
  • Await Before Use — If the module returns a promise, await it in the entry file before registering routes.
  • Keep Routes Sync — Register routes after the app exists, even if the server waits to listen.

Module Export Mixups That Trigger The Error

If quick checks didn’t fix it, the next likely culprit is how the app is exported and imported. Node can run CommonJS, ESM, or a mix that looks okay until runtime. Small differences in export style change what you get back at import time.

CommonJS Pattern That Works Reliably

Use a single module that creates the app and exports it. Then keep the file that calls listen() small and boring.

// app.js
const express = require('express')
const app = express()

app.get('/', (req, res) => {
  res.send('OK')
})

module.exports = app
// server.js
const app = require('./app')
app.listen(3000)

Adjust the import to match your export. app must be the object created by express().

ESM Pattern That Stays Consistent

If your package.json sets "type" to "module", align your exports and imports so the default export stays a default export.

// app.js
import express from 'express'
const app = express()

app.get('/', (req, res) => {
  res.send('OK')
})

export default app
// server.js
import app from './app.js'
app.listen(3000)

A mismatch here can yield undefined or an object with a default property. If your logs show a wrapper object, your import line is off by one layer.

Circular Imports That Leave You With A Half-Built Export

Circular imports are sneaky. File A imports File B, and File B imports File A. Node will hand one of them a partially built export so it can keep going. That partial export is often a plain object without methods, so app.get() breaks.

  • Search For Two-Way Imports — Look for A requiring B while B also requires A.
  • Move Routes Out — Put route handlers in a router module that does not import the server entry file.
  • Inject The App — Export a function that accepts app, then call it after creating the app.

Routing Setup Mistakes That Look Like App Problems

Sometimes your app is fine, but the file you’re editing is not the place to call app.get(). This happens when you switch to routers and forget that routers use router.get(), not app.get().

Use Router Files For Groups Of Routes

A router is created with express.Router(). It has the same method helpers, but it’s not the app. You attach it to the app with app.use().

// routes/users.js
const express = require('express')
const router = express.Router()

router.get('/', (req, res) => {
  res.send('users')
})

module.exports = router
// app.js
const express = require('express')
const app = express()
const users = require('./routes/users')

app.use('/users', users)

module.exports = app

If you imported the router module and named it app, you’ll see the error right away. Rename the variable to what it is, and the bug often fixes itself.

Mount Order And File Ownership

Keep a single “owner” file for app creation. Put route groups in routers. Put server start logic in one entry file. When the roles mix, accidental imports show up and you end up calling route methods on the wrong thing.

  • Create The App Once — Make one file responsible for express() and middleware.
  • Register Routes Next — Mount routers after middleware like JSON parsing.
  • Start Listening Last — Call listen() from the entry file, not from router modules.

Harder Cases When App Gets Replaced At Runtime

If the error appears only after certain code runs, your app variable may be getting replaced. That can happen through reassignment, a bad return value, or a pattern that overwrites properties on the app object.

Watch For Reassignment And Shadowing

Search your codebase for app =. In a healthy Express setup, you should see the assignment once, right after calling express(). If you see more, track each one. A single stray reassignment can turn the app into a config object or a result from another function call.

  • Rename Confusing Variables — Use names like server, client, or api for non-Express values.
  • Avoid Passing App As Generic Data — Don’t reuse app as an argument name in unrelated functions.
  • Freeze The Reference — Use const for the app and don’t redeclare it in inner scopes.

Check For Runtime Patching Gone Wrong

Some plugins or custom wrappers extend the app object. If code assigns app.get to a non-function value, the error will read the same. This is rare, but the fix is straightforward. Locate the assignment and remove it.

  • Search For app.get Assignments — Look for app.get = or app['get'] =.
  • Keep Settings Separate — Store config in a separate object instead of on the app instance.
  • Restart After Changes — A stale dev server can hide a fixed bug; restart to confirm the new code is running.

A Minimal Baseline To Compare Your Project Against

When you’re stuck, compare your project against a tiny working server. If the tiny server runs and your project fails, the difference points at the broken link in your imports or app creation chain.

const express = require('express')
const app = express()

app.use(express.json())

app.get('/health', (req, res) => {
  res.json({ status: 'ok' })
})

app.listen(3000, () => {
  console.log('listening on 3000')
})

Now transfer pieces from your project into this baseline one at a time. Move middleware first, routers next, database wiring last. The moment the error returns, the last piece you moved is the one handing you the wrong app value.

If you want official references, the Express API and Node module docs are the two pages worth bookmarking.

  • Open The Express API — https://expressjs.com/en/api.html
  • Open Node Module Docs — https://nodejs.org/api/modules.html

Once the app variable points at a real Express instance again, the error goes away and your routes register normally. If you still see failures after that, the next error message will usually be a normal route or middleware bug, and that’s a nicer problem to have.

Treat app creation, route registration, and server startup as separate jobs. When each job lives in its own file, the app get is not a function error has fewer places to hide.