Node 백엔드 프로젝트를 위한 tsconfig 구성
안정적인 서버 측 TypeScript 환경을 위해 컴파일러 옵션, 모듈 해석 및 경로 별칭을 조정합니다.
Node 백엔드 프로젝트를 위한 tsconfig 구성은(는) CoddyKit의 무료 Node.js Backend Development Bootcamp 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Node.js Backend Development Bootcamp 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Node.js Backend Development Bootcamp 강의에는 총 4개의 강의가 포함되어 있습니다.
이 강의의 일부는 아직 번역되지 않았으며 영어로 표시됩니다.
Why tsconfig Matters on the Server
When you run TypeScript on a Node.js backend, tsconfig.json is the single source of truth that controls how your code is type-checked and compiled to JavaScript.
- compilerOptions tune the output, strictness, and module system.
- include / exclude decide which files are part of the project.
A backend config differs from a frontend one: there is no DOM, no bundler, and Node loads the emitted JavaScript directly. Getting these options right prevents subtle runtime crashes and broken imports.
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"outDir": "dist",
"rootDir": "src",
"strict": true
},
"include": ["src/**/*"]
}Picking the Right target
The target option controls which JavaScript version the compiler emits. On a backend you are not constrained by old browsers, only by your Node.js runtime.
- Node 18 supports up to ES2022; Node 20+ supports ES2023.
- A modern
targetmeans features like top-levelawait, class fields, andArray.at()compile to native code instead of bulky polyfills.
Match target to the lowest Node version you deploy to. Setting it too high can emit syntax your runtime cannot parse.
// Works natively when target is ES2022 on Node 18+
const nums = [10, 20, 30];
console.log(nums.at(-1)); // 30
class Cache {
store = new Map(); // class field
set(k, v) { this.store.set(k, v); return this; }
}
console.log(new Cache().set("a", 1).store.get("a")); // 1module and moduleResolution
These two options decide how import and require statements are emitted and resolved.
- module: what kind of module syntax the compiler emits.
- moduleResolution: how TypeScript finds the files behind each import specifier.
For modern Node backends, "module": "NodeNext" with "moduleResolution": "NodeNext" is the recommended pair. It teaches TypeScript to respect Node's real resolution rules, including the type field in package.json and the difference between CommonJS and ESM.
{
"compilerOptions": {
"module": "NodeNext",
"moduleResolution": "NodeNext"
}
}CommonJS vs ESM Decision
The single biggest decision for a Node backend is the module system. It is driven by the type field in package.json, not by tsconfig alone.
"type": "commonjs"(or omitted): files userequire/module.exports."type": "module": files are ESM and useimport/export.
With ESM you gain top-level await and a single import syntax, but you must write explicit file extensions in relative imports. With CommonJS you get broader compatibility with older libraries. Choose ESM for new projects unless a dependency forces CommonJS.
{
"name": "my-api",
"type": "module",
"main": "dist/index.js"
}ESM Needs File Extensions
This trips up almost everyone moving to ESM. When module is NodeNext and your package is "type": "module", relative imports in your source must include the .js extension, even though the file on disk ends in .ts.
TypeScript does not rewrite import paths, so the specifier you write is exactly what Node receives at runtime. You write .js because that is the file that will exist after compilation.
// src/user.service.ts
export function findUser(id) {
return { id, name: "Ada" };
}
// src/index.ts -- note the .js extension on a .ts file
import { findUser } from "./user.service.js";
console.log(findUser(7));Turn On strict Mode
"strict": true is the most valuable option for backend reliability. It is an umbrella that enables a family of checks at once.
- strictNullChecks:
nullandundefinedare no longer assignable everywhere, catching missing-value bugs. - noImplicitAny: every value must have a known or inferable type.
- strictFunctionTypes, strictBindCallApply, and more.
On a server these checks prevent whole classes of production crashes, like reading a property off an object that could be undefined.
function getPort(env) {
// With strictNullChecks, env.PORT is string | undefined
const raw = env.PORT;
const port = raw ? Number(raw) : 3000;
return port;
}
console.log(getPort({ PORT: "8081" })); // 8081
console.log(getPort({})); // 3000outDir, rootDir, and the Build Layout
These options keep your compiled output cleanly separated from your source.
- rootDir: the base folder of your input files, usually
src. - outDir: where emitted JavaScript lands, usually
dist.
Setting rootDir guarantees the directory structure under src is mirrored exactly under dist. Without it, TypeScript infers the root from your files and a stray file outside src can shift the whole output tree, breaking your main path.
{
"compilerOptions": {
"rootDir": "src",
"outDir": "dist",
"sourceMap": true,
"declaration": false
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}Path Aliases with baseUrl and paths
Deep relative imports like ../../../config/db are fragile. Path aliases let you write stable, readable specifiers.
- baseUrl: the directory from which non-relative imports are resolved.
- paths: a map of alias patterns to real folders.
A common convention is to map @/* to src/*, so any module can import from @/services/user.service.js regardless of its own depth.
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
}
}Aliases Don't Exist at Runtime
Here is the critical gotcha: paths only affects type-checking. The TypeScript compiler does not rewrite @/services/user.service.js into a real relative path in the emitted JavaScript.
So Node will fail at runtime with a module-not-found error unless you bridge the gap. Common solutions:
- A runtime resolver like
tsconfig-paths(CommonJS) or a loader. - A bundler such as
tsuporesbuildthat inlines the aliases. - A post-build step that rewrites the paths.
Always remember: tsconfig describes types; the runtime needs its own plan for aliases.
Node Types and Speeding Up Builds
To use globals like process, Buffer, and the fs module with full typing, install @types/node and let TypeScript pick them up.
- types: restrict which global type packages are included (for example, just
["node"]). - skipLibCheck: skip type-checking of
.d.tsfiles in dependencies, dramatically cutting build time. - esModuleInterop: lets you write
import express from "express"for CommonJS default exports.
{
"compilerOptions": {
"types": ["node"],
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true
}
}A Complete Backend tsconfig
Putting it all together, here is a robust starting point for a modern ESM Node.js backend. It compiles src to dist, enforces strictness, and uses Node-native resolution.
Pair this with "type": "module" in package.json and a build script of tsc -p tsconfig.json. Remember to handle path aliases at runtime if you enable paths.
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"rootDir": "src",
"outDir": "dist",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"sourceMap": true,
"types": ["node"],
"baseUrl": ".",
"paths": { "@/*": ["src/*"] }
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}Quick Check
Test your understanding of path aliases in a Node backend build.
Recap
You now know how to configure tsconfig.json for a server-side TypeScript project.
- target: match your lowest Node version (ES2022 for Node 18+).
- module / moduleResolution: use
NodeNextfor honest Node resolution. - type field in package.json drives CommonJS vs ESM; ESM relative imports need
.jsextensions. - strict: turn it on to catch null and any bugs before production.
- rootDir / outDir: keep a clean
srctodistbuild layout. - paths: great for readability, but aliases must be resolved at runtime by a loader or bundler.
With these options dialed in, your Node backend gets reliable type safety and a predictable build.
자주 묻는 질문
“Node 백엔드 프로젝트를 위한 tsconfig 구성” 강의는 무료인가요?
네 — “Node 백엔드 프로젝트를 위한 tsconfig 구성” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Node.js Backend Development Bootcamp 강의 전체를 잠금 해제할 수 있습니다. Node.js Backend Development Bootcamp 강의에는 총 4개의 강의가 포함되어 있습니다.
“Node 백엔드 프로젝트를 위한 tsconfig 구성”에서 뭘 배우나요?
안정적인 서버 측 TypeScript 환경을 위해 컴파일러 옵션, 모듈 해석 및 경로 별칭을 조정합니다. 브라우저에서 직접 실행하는 실습 코드로 Node.js Backend Development Bootcamp을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Node.js Backend Development Bootcamp을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Node.js Backend Development Bootcamp은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.
“Node 백엔드 프로젝트를 위한 tsconfig 구성” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Node.js Backend Development Bootcamp 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Node.js Backend Development Bootcamp 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- CommonJS에서 네이티브 ES 모듈로 마이그레이션
- Node 백엔드 프로젝트를 위한 tsconfig 구성
- 타입 안전 환경 구성 및 런타임 검증
- tsx, 핫 리로드 및 소스 맵으로 빠르게 반복하기