| | |

Bun 03 ⚡ Initializing Projects and package.json Integration

⏱️ Estimated read: 9 min | |

Bun’s project initialization is designed to eliminate the configuration burden that Node.js projects typically carry. Running bun init generates a complete, working project with sensible defaults, and it integrates with package.json in ways that differ from npm and Yarn: it writes a typecheck script, it understands workspaces natively, and it defaults to treating package scripts as first-class commands. The package.json that Bun produces is still a standard Node.js manifest, but the integration layer—how Bun reads, writes, and executes it—is optimized for the runtime.

Key point: bun init is non-destructive and infers settings from the directory. It creates an entry point, a TypeScript configuration, and a package.json with a typecheck script, then runs bun install to install @types/bun and typescript. The resulting manifest works with Node.js and npm, but Bun reads it differently.


Why Bun’s initialization differs

The zero-config problem. A Node.js project requires a package.json, a tsconfig.json (for TypeScript), an entry point, and a test configuration. Each file has its own schema and its own documentation. bun init generates all of them from a single interactive prompt. The tsconfig.json is preconfigured for Bun’s features: moduleResolution: "bundler", allowImportingTsExtensions, and types: ["bun"] . A developer can start writing TypeScript immediately without editing configuration files.

The entry point inference problem. bun init does not arbitrarily choose index.ts. It checks for existing entry points (index.tsx, index.jsx, index.js, index.mts, index.mjs) and uses the one it finds. If none exist, it defaults to index.ts. If package.json already specifies a module or main field, that entry point is used . This means running bun init in an existing project does not break the existing structure—it fills in the missing pieces.

The script execution problem. In npm, running npm run dev spawns a subshell, locates the script in package.json, and executes it. In Bun, bun dev is the equivalent of bun run dev unless dev conflicts with a built-in Bun command. Bun’s startup time for scripts is approximately 6ms, compared to npm’s 170ms . The package.json scripts are the same; the execution engine is different.

The workspace problem. Bun’s package.json integration extends to workspaces. The workspaces field in the root manifest lists the glob patterns for sub-packages. Bun supports full glob syntax, including negative patterns (!packages/**/test/**), and it deduplicates dependencies across workspaces during bun install . The workspace protocol (workspace:*) is replaced with the actual version during publishing, just as pnpm does.

The trade-off. Bun’s defaults are optimized for Bun. A package.json created by bun init includes a typecheck script that runs bun check, which is a Bun-specific command. The tsconfig.json includes "types": ["bun"], which requires @types/bun. Projects that need to run under Node.js must ensure the configuration does not depend on Bun-only features.


a. Running bun init and understanding the output

bun init is interactive by default. It prompts for a project template (Blank, React, or Library) and then generates the files. The -y flag accepts the defaults without prompting .

# Interactive
bun init

# Accept defaults
bun init -y

# Initialize in a specific directory
bun init my-app

The files created depend on the template and the existing directory contents. For a blank template in an empty directory, Bun creates:

  • package.json with a name derived from the directory and a typecheck script
  • tsconfig.json with Bun’s recommended compiler options
  • index.ts as the entry point
  • README.md
  • .gitignore

It then runs bun install to install @types/bun and typescript as dev dependencies .

The bun init command is non-destructive. Running it in an existing project does not overwrite files that already exist. It fills in the missing configuration files and updates package.json only where necessary .


b. The package.json that bun init produces

The generated package.json is minimal but functional. It includes name, version, type: "module", and a typecheck script that invokes bun check. The type: "module" field makes the project an ES module by default, matching the direction of modern Node.js and Bun’s native ESM support.

{
  "name": "my-app",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "typecheck": "bun check"
  },
  "devDependencies": {
    "@types/bun": "latest",
    "typescript": "^5.0.0"
  }
}

The typecheck script is a Bun-specific addition. bun check runs the TypeScript compiler in check-only mode, using the tsconfig.json that bun init generated. This script is what makes the package.json “Bun-aware” while remaining compatible with npm and Node.js—the script is just a string, and the dependencies are standard npm packages.

For React projects, bun init --react generates a package.json with react and react-dom dependencies, and a tsconfig.json configured for JSX ("jsx": "react-jsx"). The --react=tailwind and --react=shadcn presets add the corresponding dependencies and configuration .


c. Integrating package.json with Bun’s runtime

Bun reads package.json fields that npm and Yarn ignore, and it interprets some fields differently. The scripts field is the most important. bun run <script> executes the script in a subshell, respecting pre and post hooks. If predev exists, it runs before dev; if it fails, dev does not run .

Bun also respects the trustedDependencies field in package.json. Unlike npm and Yarn, Bun does not execute lifecycle scripts (postinstall, preinstall) by default. A package that needs to run a script must be listed in trustedDependencies. This is a security measure: it prevents arbitrary code execution during installation .

{
  "trustedDependencies": ["esbuild", "sharp"]
}

The workspaces field is fully supported. Bun’s workspace resolution deduplicates dependencies and links workspace packages. The workspace:* protocol is replaced with the actual version during bun publish, matching the behavior of pnpm and Yarn Berry .

The overrides and resolutions fields are also read. overrides is npm’s mechanism for pinning transitive dependencies; resolutions is Yarn’s. Bun supports both, preferring overrides when both exist . This allows projects migrating from npm or Yarn to keep their existing override rules without modification.


Complete Example Session

# ============================================
# PART 1: INITIALIZE A PROJECT
# ============================================

mkdir my-bun-app && cd my-bun-app
bun init -y
# Creates package.json, tsconfig.json, index.ts, README.md
# ============================================
# PART 2: INSPECT PACKAGE.JSON
# ============================================

cat package.json
# {
#   "name": "my-bun-app",
#   "version": "1.0.0",
#   "type": "module",
#   "scripts": { "typecheck": "bun check" },
#   "devDependencies": { ... }
# }
# ============================================
# PART 3: INSPECT TSCONFIG
# ============================================

cat tsconfig.json
# Includes "types": ["bun"], "moduleResolution": "bundler"
# ============================================
# PART 4: RUN THE ENTRY POINT
# ============================================

bun run index.ts
# Executes TypeScript without transpilation.
# ============================================
# PART 5: ADD A SCRIPT
# ============================================

# Edit package.json:
# "scripts": { "dev": "bun run index.ts" }
bun dev
# Bun runs the script (or bun run dev).
# ============================================
# PART 6: TRUST A NATIVE PACKAGE
# ============================================

# Add to package.json:
# "trustedDependencies": ["esbuild"]
bun add esbuild
# postinstall script runs because esbuild is trusted.
# ============================================
# PART 7: CONFIGURE WORKSPACES
# ============================================

# Root package.json:
# "workspaces": ["packages/*"]
bun install
# Dependencies for all workspaces are installed.
# ============================================
# PART 8: USE OVERRIDES
# ============================================

# package.json:
# "overrides": { "bar": "4.4.0" }
bun install
# Transitive dependency bar is pinned to 4.4.0.
# ============================================
# PART 9: TYPECHECK
# ============================================

bun run typecheck
# Runs bun check, reports TypeScript errors.

The nine parts trace initialization, configuration inspection, entry point execution, script addition, native dependency trust, workspace setup, overrides, and type checking. Each step modifies package.json and observes Bun’s interpretation of it.


Quick Reference

bun init Flags

FlagEffect
-y / --yesAccept defaults without prompting
--reactScaffold a React project
--react=tailwindReact + Tailwind CSS
--react=shadcnReact + shadcn/ui + Tailwind

Generated Files

FilePurpose
package.jsonManifest with typecheck script
tsconfig.jsonBun-recommended compiler options
index.tsDefault entry point
README.mdProject readme
.gitignoreIgnore patterns

package.json Fields Bun Reads

FieldBehavior
scriptsRun with bun run or bun <script>
trustedDependenciesAllow lifecycle scripts
workspacesMonorepo support with glob
overridesPin transitive dependencies
resolutionsYarn-compatible overrides

Best Practices

✅ Do This:

bun init -y
<!-- Non-interactive initialization -->              # ✅
{ "trustedDependencies": ["esbuild"] }
<!-- Explicitly trust native packages -->             # ✅
bun run typecheck
<!-- Type check before committing -->                # ✅

❌ Don’t Do This:

# Assume lifecycle scripts run by default
<!-- Bun blocks them for security -->                # ❌
# Edit tsconfig.json without understanding Bun's defaults
<!-- The generated file is already configured -->     # ❌
# Run bun init in a non-empty directory without checking
<!-- It is non-destructive, but review the changes --> # ❌

Common Pitfalls

PitfallWhy It HappensFix
Native module failsLifecycle script blockedAdd to trustedDependencies
Type errors on Bun global@types/bun not installedbun add -d @types/bun
bun dev runs built-in instead of scriptName collisionUse bun run dev
Workspace dependency not foundNot declared in workspace manifestAdd with workspace:*
TypeScript 6+ types not foundtypes array missing "bun"Add "types": ["bun"] to tsconfig

Real-World Examples

1. Initialize

bun init -y

2. React Scaffold

bun init --react=tailwind

3. Run Script

bun dev

4. Trust Package

{ "trustedDependencies": ["sharp"] }

5. Workspace Root

{ "workspaces": ["packages/*"] }

6. Override

{ "overrides": { "lodash": "4.17.21" } }

7. Typecheck

bun check

8. Add Types

bun add -d @types/bun

9. Entry Point Inference

# Bun uses index.tsx if it exists

10. Inspect Manifest

cat package.json

Visual

bun init Flow

┌──────────────────────────────────────────────┐
│  bun init                                    │
└──────────────────┬───────────────────────────┘
                   │
                   ▼
┌──────────────────────────────────────────────┐
│  Detect existing files                       │
│  ├─ index.tsx? → use as entry                │
│  ├─ index.js? → use as entry                 │
│  └─ none → create index.ts                   │
└──────────────────┬───────────────────────────┘
                   │
                   ▼
┌──────────────────────────────────────────────┐
│  Generate package.json, tsconfig.json        │
│  README.md, .gitignore                       │
└──────────────────┬───────────────────────────┘
                   │
                   ▼
┌──────────────────────────────────────────────┐
│  bun install (typescript, @types/bun)        │
└──────────────────────────────────────────────┘

package.json Interpretation

┌──────────────────────────────────────────────┐
│  package.json                                │
│                                              │
│  scripts → bun run <script>                  │
│  trustedDependencies → allow postinstall     │
│  workspaces → monorepo linking               │
│  overrides → pin transitive deps             │
└──────────────────┬───────────────────────────┘
                   │
                   ▼
┌──────────────────────────────────────────────┐
│  Bun reads fields that npm ignores           │
│  (trustedDependencies, workspace protocol)   │
└──────────────────────────────────────────────┘

Summary

ItemValue
Init commandbun init
Non-interactive-y / --yes
Default entryindex.ts (or existing)
Generated tsconfigBun-recommended options
Generated script"typecheck": "bun check"
Lifecycle scriptsBlocked unless in trustedDependencies
Workspacesworkspaces field with glob
Overridesoverrides or resolutions

Key takeaways:

  • bun init is non-destructive and infers entry points. It checks for existing files and uses them rather than overwriting. The result is a working project with minimal configuration .
  • The generated package.json is Bun-aware but Node.js-compatible. The typecheck script and trustedDependencies field are Bun-specific, but the file remains a standard npm manifest.
  • Lifecycle scripts are blocked by default. Packages that need postinstall must be listed in trustedDependencies. This is a security measure that changes the migration workflow for native modules .
  • Workspaces and overrides are first-class. Bun reads workspaces with full glob support and honors both npm overrides and Yarn resolutions .
  • TypeScript 6+ requires explicit type configuration. The tsconfig.json must include "types": ["bun"] for the Bun global to be recognized .

Remember: bun init is not just a scaffolding command. It configures the package.json for Bun’s interpretation: scripts run faster, lifecycle scripts are gated by trust, workspaces are deduplicated, and overrides are respected. The manifest remains portable, but the integration layer is Bun-specific.

Was this helpful?


Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!