Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

The most reliable local-development setup is a dedicated Dockerfile development stage selected by Compose, with dependencies cached, source files synchronized, and stateful services such as PostgreSQL kept in their own containers. Use Compose Watch when you want controlled per-path updates; use a bind mount when you need direct host-to-container filesystem sharing.

This arrangement lets you edit on the host, run the Node.js process inside a consistent container, preserve database data across restarts, and attach a debugger without mixing development-only tooling into the production image.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What the development workflow looks like

A development container has different requirements from a production runtime. It needs hot-reload tooling, source-code feedback, debugger access, and usually all development dependencies. A production image instead aims to be small and contains only the files and packages required to run the built application.

Use a multi-stage Dockerfile with a stage named dev. Your Compose service builds that target, publishes the application port, and defines either Compose Watch rules or bind mounts for source changes. Keep the database as a separate service with a named volume for durable data. The resulting flow is:

#1 Best Overall
Sale
Compressed Air Duster,130000RPM Super Power Cordless Air Duster,Rechargeable Brushless Blower,3 Gear Adjustable Blower with LED Light,Dust Remover for Computer/House/Outdoor/Car
  • Powerful Turbo Fan:CAGIWIRU Electric Air Duster have reached speed up to 130000RPM,Can efficient remove dust and debris.With LED light and Three Adjustable Speed to meet with different cleaning tasks.
  • With Attached USB C Fasting Charging cable.Charing 3 hours,Enjoy up to 240 minutes of use on the lowest setting, For third speed can use for 25mins.with four charging options to meet with your needs.
  • Wide Application: attached 5 different nozzles,making it suitable for a variety of scenes, such as car,pet, pc, keyboards, and other electronic devices. It also serves for office and home clean duster.
  • Handy Design & Portable:Cordless air duster electric nozzle is Light weight and small size, design and comfortable to hold and space saving, convenient to carry around. You can put it in your room or inside the car without taking up space.
  • Economical &Reusable: Built durable materials with a long-lasting battery,our CAGIWIRU air duster it's a sustainable alternative to disposable air cans.
  • Docker builds the dev stage and installs npm dependencies.
  • Compose starts the Node.js service and any supporting services.
  • Compose Watch synchronizes selected paths, or a bind mount shares the working tree directly.
  • The Node process runs the project’s development script and listens on a container interface such as port 3000.
  • A debugger attaches through a published inspector port, commonly 9229.

Prerequisites and project assumptions

You need a current Docker Engine or Docker Desktop installation with the Compose plugin, a Node.js project containing package.json, and a development command such as npm run dev. The examples assume the application listens on port 3000 inside the container and that the source code is in a directory named src. Change those values to match your project.

Commit a lockfile, normally package-lock.json, if reproducible installs matter. Without a lockfile, npm resolves versions again during each dependency installation, so two builds can receive different transitive versions.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Create a development Dockerfile

Place this file at the project root as Dockerfile:

# syntax=docker/dockerfile:1
FROM node:24-alpine AS dev
WORKDIR /app
RUN --mount=type=cache,target=/root/.npm 
    --mount=type=bind,source=package.json,target=package.json 
    --mount=type=bind,source=package-lock.json,target=package-lock.json 
    npm ci
COPY . .
EXPOSE 3000
CMD ["npm", "run", "dev"]

Why each instruction is there

  • FROM node:24-alpine AS dev selects a current Node 24 Alpine development image and gives the stage the name Compose will target. Choose and periodically refresh the Node tag according to your project’s supported version policy.
  • WORKDIR /app makes /app the working directory for dependency installation and the application process.
  • The cache mount at /root/.npm retains downloaded npm packages between eligible builds. It avoids repeatedly downloading the same tarballs while keeping the image layers clean.
  • The bind mounts expose only the manifest files to the install step. Because dependency metadata changes less often than application source, Docker can reuse the install layer when you edit source files.
  • npm ci installs exactly what the lockfile specifies and is appropriate for a clean, repeatable install.
  • COPY . . adds the rest of the project after dependencies have been installed, preserving the cache-friendly layer order.
  • EXPOSE 3000 documents the port used by the process; Compose still needs a port mapping to make it reachable from the host.
  • The final command starts the project’s development script. If your project uses a different script, replace dev with that script name.

If you do not have a lockfile

Do not reference a nonexistent package-lock.json in a bind mount. Bind only package.json and run npm install until you generate and commit a lockfile. Then switch to the two-manifest mounts and npm ci shown above.

Add a .dockerignore file

Keep host-generated files out of the build context. A practical starting point is:

node_modules
npm-debug.log
.git
.env
coverage

Do not ignore files that the image must copy at build time, such as your source directory, configuration templates, or the lockfile.

Define the Compose development service

Create compose.yaml with a service that explicitly targets the development stage:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #2
EVEO® Screen Cleaner Spray Kit (Streak-Free) TV Screen Cleaner for Smart TV, Lcd, LEd, Oled | Computer Screen Cleaner Spray and Wipe Microfiber Cloth - TV, Monitor, Laptop, iPad, Car - 6.7oz 1 Pack
  • Screen Cleaner is Your Screen’s New Bestfriend! - EVEO is proud to present a screen cleaner that’s perfectly suited for your TV. Meet your new screen cleaner, computer screen cleaner, laptop cleaner, iPad cleaner, Macbook,tv cleaner or any other electronic device. Our screen cleaner spray and wipe along with the included plush microfiber cloth, easily removes dust, fingerprints & other smudges on the screen’s surface. Clean effectively for a streak-free screen
  • Gentle on your Screens - Our screen cleaner spray and wipes is compatible to be used even for the most sensitive LCD, LED, CRT, and OLED screens in proper use. Be at ease knowing that this product is compatible with all the major brands: LG, SONY, Samsung, Sharp, iPad, iPhone, Android screens, Kindle, PC monitors - we’ve got you covered! Can be used as LCD screen cleaner, tv cleaner, smart tv screen cleaner, and more
  • Premium Super Soft Plush Microfiber Cloth - Included in this efficient screen cleaning kit. This screen cleaner spray and wipe has our signature plush microfiber cloth specially designed to comply with screens and monitors and leave them streak-free. Has been shown to effectively absorbs stubborn stains, zero streaks, and no fiber shedding. Always use this together with our screen cleaner for the best results
  • Easy-to-Use Screen Cleaner Kit + microfiber cleaning cloth - The EVEO Screen Cleaning Kit will easily be your new favorite tool when it comes to taking care of the things you love most, quick and easy solution for a streak-free screen. Simply screw on the sprayer gun on the screen cleaner bottle. Spray the cleaning liquid onto the microfiber cloth, then wipe the screen until desired cleanliness & shine is achieved.
  • Quality Screen Care Kit Worth Purchasing - Enjoy a convenient Screen Cleaner anytime, anywhere you need it. Your satisfaction is our top priority. We stand behind the quality of our products and that’s why, you shouldn’t be worrying at all. We manufacture the Best Screen Cleaner. and can be used for laptop cleaning kit, laptop screen cleaner, tv screen cleaner for smart tv. MacBook screen cleaner, monitor cleaner or screen cleaner spray for electronic devices with microfiber cleaning cloth
services:
  app:
    build:
      context: .
      target: dev
    ports:
      - '3000:3000'
    develop:
      watch:
        - action: sync
          path: ./src
          target: /app/src
        - action: rebuild
          path: package.json

The target: dev setting prevents Compose from accidentally using a production stage. The port mapping exposes host port 3000 and forwards it to port 3000 in the container. The watch rules synchronize source edits without rebuilding the image, while a manifest change triggers a rebuild so the dependency layer is recreated.

Compose Watch is intended for services that are built locally. Start it with:

docker compose watch

On Compose versions that support the combined command, you can use:

docker compose up --watch

Run docker compose config before starting if you want Compose to render and validate the merged configuration.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Build, start, and verify the app

  1. From the directory containing Dockerfile and compose.yaml, run docker compose build app. The first build downloads the base image and npm packages; later builds can reuse the npm cache and unchanged layers.
  2. Start the service with docker compose up if you are using a separate watch process, or use docker compose watch to build and monitor according to your installed Compose behavior.
  3. Open http://localhost:3000. If the app is not reachable, verify that the Node server binds to 0.0.0.0 inside the container rather than only to 127.0.0.1.
  4. Edit a file under src. A sync rule copies the change to /app/src; your development runner must watch that path and restart or reload the process.
  5. Edit package.json or the lockfile. The rebuild rule recreates the image so newly declared packages are installed.
  6. Stop the stack with Ctrl+C, or run docker compose down from another terminal. A normal down does not remove named database volumes.

Compose Watch versus bind mounts

Both mechanisms can provide fast feedback, but they solve different problems. Docker describes a bind mount as a host file or directory mounted into a container, which is useful when you need direct sharing of source code or build artifacts. Compose Watch lets you declare explicit actions for particular paths; Docker notes that it provides greater granularity than is practical with a bind mount.

Consideration Compose Watch Bind mount
Update granularity Per-path actions such as sync and rebuild; unrelated files can be excluded. The mounted directory is shared as a whole unless you add additional mount structure.
node_modules You can leave it inside the container and avoid synchronizing the large tree. A broad project mount can hide container-installed dependencies unless you add a separate volume for /app/node_modules.
Cross-platform behavior Controlled synchronization can avoid some host/container filesystem and compiled-artifact mismatches. Direct sharing may incur higher I/O overhead or expose platform-specific files.
Dependency changes A manifest rule can trigger an image rebuild explicitly. Changing a manifest does not install packages automatically; you must rebuild or run an install command.
Service requirement Designed for services built locally. Can be used with a running container regardless of how its image was built.
Best fit Selective source synchronization and predictable actions. Tools that require immediate, direct host-container file sharing.

A bind-mount alternative

If your editor, generator, or build tool needs the complete working tree immediately, add a volume configuration to the app service:

Rank #3
Sale
BladeHawks RGB Gaming Mouse Pad Extra Large Extended 31.5x12 Inch-Black | LED mouse pad with 14 lighting modes, covers keyboard & mouse, anti-slip rubber base, waterproof surface, USB powered
  • 【Large size】:Measuring 800 x 300 mm/ 31. 5×12 inches, which is wider and taller than others. Large mouse pad can perfectly fit your keyboard and mouse of any size, and there is also ample space for peripherals such as phones, tablets, etc.
  • 【LED backlight mouse pad】:Blade Hawks RGB mouse pad provides 7 static modes and 7 dynamic modes will give you the options you are looking for. Power-off memory function remembers the last lighting mode you selected. The super glow fiber Chroma will give you a colorful gaming setup that you want.
  • 【Anti-slip rubber base】:Made from Natural rubber, this gaming mousepad will firmly grip your desktop, allowing you to enjoy the ultimate precision in the games you are most passionate about. It also comes with a texture that enhances this ability even further.
  • 【Smooth and waterproof surface】: Micro-textured cloth surface, for extremely precise mouse control and a smooth movement. When liquid splashes on the gaming mouse pad, it forms water droplets and slides down. Will not delay your work or gameplay.
  • 【Plug and play】: This mouse and keyboard pad is powered by USB, plug and play, no driver required. One button control light modes. Press one time to change the lighting mode, press twice to change the brightness, press and hold about 3 seconds turn ON/OFF.
services:
  app:
    build:
      context: .
      target: dev
    ports:
      - '3000:3000'
    volumes:
      - type: bind
        source: .
        target: /app
      - type: volume
        target: /app/node_modules
    command: npm run dev

The second, anonymous volume keeps the container’s Linux-installed dependencies from being replaced by a host node_modules directory. This setup is simple, but the broad bind mount can increase filesystem traffic and can expose compiled modules built for the host platform. Use narrow mounts or Compose Watch when those effects become noticeable.

Keep dependency installation fast and reproducible

Use the lockfile deliberately

With package-lock.json committed, npm ci removes any existing dependency tree and installs the locked versions. Treat lockfile edits as dependency changes that require a rebuild. If a package is added on the host but the image is not rebuilt, the running container will still have the old dependency set.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Preserve the cache mount

The BuildKit cache mount stores npm’s downloaded package data outside the image layer. It speeds subsequent builds without copying the cache into the final image. Cache contents are an optimization, not a substitute for the lockfile; a clean machine must still be able to install from the registry.

Never synchronize node_modules

Compose’s documentation specifically cautions against synchronizing node_modules. The directory can contain hundreds of thousands of files, creating high I/O load, and native or compiled artifacts may not be portable between the host operating system and the container. Install dependencies in the container and synchronize source instead.

Add PostgreSQL without losing development data

Keep the database in its own Compose service. The following extension uses a health check, a dependency condition, a named data volume, and a file-backed password secret:

services:
  app:
    build:
      context: .
      target: dev
    ports:
      - '3000:3000'
    environment:
      DATABASE_URL: postgresql://appuser:change-me@db:5432/appdb
    depends_on:
      db:
        condition: service_healthy
    develop:
      watch:
        - action: sync
          path: ./src
          target: /app/src
        - action: rebuild
          path: package.json
        - action: rebuild
          path: package-lock.json

  db:
    image: postgres:16
    environment:
      POSTGRES_USER: appuser
      POSTGRES_DB: appdb
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password
    volumes:
      - db_data:/var/lib/postgresql/data
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -U appuser -d appdb']
      interval: 5s
      timeout: 5s
      retries: 10

volumes:
  db_data:

secrets:
  db_password:
    file: ./secrets/db_password.txt

Replace the example connection string and credentials with values appropriate for your project. The important details are that the app connects to the Compose service name db, startup waits for a healthy database rather than merely a running container, and db_data survives routine container recreation. Do not run docker compose down -v unless you intentionally want to delete that volume and its data.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #4
Sale
Vaydeer Wrist Rest for Keyboard and Mouse, Computer Ergonomic Wrist Support Pad, Soft Memory Foam Arm Cushion for Desk, Palm Hand Office Laptop Typing
  • 【Softer and More Comfortable】Vaydeer wrist rest has unique diamond pattern, which is the combination of softness and aesthetics. The materials of wrist rest are improved into higher quality memory foam and covered with silky smooth lycra. The computer wrist rest makes you as comfortable and cushiony as like rest your wrists on clouds.
  • 【Ergonomic Wrist Saver】The wrist rests for keyboard and mouse comes with a 17.32×3.15×0.83 inch keyboard wrist pad and a 5.94×3.15×0.83 inch mouse wrist support. Based on ergonomic design, the unique concave shape is the perfect fit for your wrist joints. The wrist rest pad fits most computer keyboards and laptops, improve hand and wrist posture, release your wrist and arm stress.
  • 【Non-Slip Rubber Bottom】Featuring an anti-skid silicone base on the bottom, this wrist keyboard support stays firmly in place on your desk, preventing the padding from sliding around, ensuring stable and consistent wrist support during extended computer sessions.
  • 【Better Experience & Pain Relief】Our keyboard arm rest is beneficial to alleviate the soreness caused by direct contact and friction between your arm and a hard desk surface, reducing the risk of wrist fatigue or carpal tunnel. The soft texture of memory foam can evenly distribute the pressure around your wrists and provide good support with just enough give.
  • 【Helpful in Multiple Scenarios】Whether you're working, studying, writing, typing, gaming, this keyboard and mouse rest combo is an essential accessory to add comfort and support to your hands and wrists. It’s also a great gift for men, women, family, friend, coworker, gamer, teacher, etc.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Attach a Node.js debugger

Publish the inspector port and start Node with an address reachable from outside the container. Add the port to Compose:

services:
  app:
    ports:
      - '3000:3000'
      - '9229:9229'

Then make the development command invoke the inspector, for example:

node --inspect=0.0.0.0:9229 ./node_modules/.bin/your-dev-runner

Use the equivalent command for your framework’s development runner. Binding the inspector to 0.0.0.0 is necessary because 127.0.0.1 inside the container is not the host machine.

Attach from VS Code

Create a launch configuration that attaches to port 9229:

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
{
  "type": "node",
  "request": "attach",
  "name": "Attach to Node in Docker",
  "address": "localhost",
  "port": 9229,
  "localRoot": "${workspaceFolder}",
  "remoteRoot": "/app"
}

Start the Compose service, set a breakpoint, and select this configuration in VS Code. The localRoot and remoteRoot mappings let the debugger translate host paths to container paths.

Attach from Chrome DevTools

Open Chrome’s inspection page and connect to the Node inspector endpoint on localhost:9229. Select the running target, set breakpoints in the loaded source, and verify that source maps point to your local files when the project transpiles TypeScript or another language.

Best Value
Sale
Under Desk Cable Management Tray No Drill, Metal Mesh Cable Management Under Desk with Clamp Mount, 2 Hole Cable Tray with Wire Management and Cord Organizer for Home Office Standing Desk
  • 【No Drill Mounted】Cable management tray can be assembled in as little as 3 minutes or less-simply. Side clips easily clampe the edge of desk, pass through the holes on the sides, and secure excess cables with baskets. Desk cable management supports inward or outward installation to meet your needs in different scenarios, and provides you with great convenience when collecting and organizing wires.
  • 【Rubber Pad Protects Desk】Wire organizer under desk built-in soft rubber pads on the clamp protect your desk from scratches, so you will not damage your furniture or office.
  • 【Sturdy and Beautiful】Cord management under desk is made of high-quality carbon steel and holds about 15 lbs. The wire basket has 2 holes on each side of the tray to enable your cables to pass freely. Cable baskets are suitable for desk thickness use from 0.4" to 2.4".
  • 【Space Saving & Keep Organized】Desk cable management tray holds all your power cords, outlet strips, USB hubs and computer transformers hidden from your feet, and the data cables will not enter the vacuum cleaner to keep your desk clean and tidy. Desk wire organizer is also suitable for use in the kitchen and outdoors.
  • 【Reduce Safety Risks】Cable tray under desk keeps all plugs away from your kids, no more worry about tripping. Using 2 holes wire tray saves extra space, helps you easily cabling and wire protection. The mesh design is not easy to accumulate dust, but avoids safety accidents caused by messy wires.

Handle configuration and private npm packages safely

Keep ordinary runtime configuration in Compose environment variables, an uncommitted local environment file, or mounted secrets. Never commit database passwords, API keys, or private registry tokens to the repository.

Do not place a private npm token in a normal Dockerfile ENV instruction or an unprotected build layer. npm recommends Docker build secrets for private modules. A BuildKit-enabled install can use a secret-mounted npm configuration, for example:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc npm ci

The exact secret declaration and command-line syntax varies with the Dockerfile and Compose versions in use, so validate it against the current Docker documentation for your installed versions. The essential property is that the credential is available only to the install step and is not copied into the resulting image layers.

Keep production separate from development

A single development image is convenient locally but is usually the wrong production artifact. Development needs hot-reload packages, source synchronization, and an inspector; production should contain compiled output and production-only dependencies.

Stage Purpose Typical contents
dev Local iteration Development dependencies, source tree, watch command, optional debugger.
deps Dependency preparation Locked npm installation that can be reused by later stages.
runner Production runtime Built application output and production dependencies in a smaller runtime image.

Compose should continue targeting dev for local work. A production build can target runner separately, copy only compiled output, and omit source-watch rules and debugging ports.

Troubleshoot the common failure modes

The container starts but the browser cannot connect

  • Confirm the process listens on port 3000 inside the container and that Compose maps 3000:3000.
  • Change the application host binding to 0.0.0.0 rather than loopback-only 127.0.0.1.
  • Inspect logs with docker compose logs -f app.

Source edits do not reload

  • Check that the edited path is covered by a Watch sync rule or a bind mount.
  • Verify that the development runner watches /app/src and is not ignoring container filesystem events.
  • On a broad bind mount, ensure the mount has not hidden files the image needs, especially /app/node_modules.

A newly installed package is missing

  • Confirm the manifest change triggered a rebuild rule.
  • Run docker compose build --no-cache app only when you need to discard all cached layers; otherwise a normal build is faster.
  • Check that the lockfile and package.json are both in the build context and agree with one another.

Native modules fail after switching hosts

Remove host-created node_modules and reinstall inside the container. Do not synchronize that directory from the host. A container-built dependency tree matches the container’s operating system and architecture.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The app races the database at startup

A plain depends_on controls startup order but does not prove that PostgreSQL is ready to accept connections. Add the database health check and use the service_healthy condition shown above. Applications should still retry transient connection failures because health checks cannot cover every initialization or network event.

The database disappeared

Check that the database uses a named volume and that you did not run docker compose down -v. Recreating a container is expected; deleting its named volume is the destructive operation.

The debugger cannot attach

  • Publish port 9229 and start Node with --inspect=0.0.0.0:9229.
  • Make sure another process is not already using host port 9229.
  • Use matching local and remote source roots so breakpoints resolve to files under /app.

Pre-flight checklist

  • The Compose service builds the dedicated dev target.
  • The Dockerfile installs dependencies before copying frequently changed source files.
  • A committed lockfile is paired with npm ci where reproducibility is required.
  • Npm downloads use a BuildKit cache mount.
  • Compose Watch synchronizes source paths and rebuilds on manifest changes, or bind mounts are intentionally scoped.
  • node_modules remains inside the container rather than being synchronized from the host.
  • The application port and, when needed, inspector port are published.
  • Database data is stored in a named volume and startup uses a health condition.
  • Passwords and npm credentials are supplied as runtime or build secrets, not committed or baked into ordinary layers.
  • Production uses a separate runner stage without development watchers and debugger exposure.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.