Skip to content

Default TypeScript template fails at runtime: ColumnDefinitions is not a runtime export #1578

@shimscho

Description

@shimscho

Bug Description

The default TypeScript migration template (templates/migration-template.ts) uses a value import for ColumnDefinitions, but ColumnDefinitions is only exported as a type from the package — it has no runtime representation in the compiled JavaScript bundle.

Template (current)

import { ColumnDefinitions, MigrationBuilder } from 'node-pg-migrate';

export const shorthands: ColumnDefinitions | undefined = undefined;

export async function up(pgm: MigrationBuilder): Promise<void> {}

export async function down(pgm: MigrationBuilder): Promise<void> {}

Error

When running migrations with tsx (or Node.js 22.6+ --experimental-strip-types), the generated migration file fails at runtime:

SyntaxError: The requested module 'node-pg-migrate' does not provide an export named 'ColumnDefinitions'

Root Cause

In dist/bundle/index.d.ts, ColumnDefinitions is exported with the type modifier:

export { ..., type ColumnDefinitions, ... }

In dist/bundle/index.js, ColumnDefinitions is not exported at all — it's a TypeScript interface with no runtime representation.

The library's own source code correctly uses import type { ColumnDefinitions } in src/migration.ts:

import type { ColumnDefinitions } from './operations/tables';

But the template uses a value import (import { ColumnDefinitions }), which is inconsistent.

Why this breaks

  • With traditional tsc compilation, TypeScript erases ColumnDefinitions from the import because it's only used as a type annotation → works
  • With tsx, swc, or Node.js native type stripping, the import binding is checked against the module's actual exports at the ESM level before types are erased → fails

Suggested Fix

Change the template to use import type:

import type { ColumnDefinitions, MigrationBuilder } from 'node-pg-migrate';

export const shorthands: ColumnDefinitions | undefined = undefined;

export async function up(pgm: MigrationBuilder): Promise<void> {}

export async function down(pgm: MigrationBuilder): Promise<void> {}

Or split the imports:

import type { ColumnDefinitions } from 'node-pg-migrate';
import { MigrationBuilder } from 'node-pg-migrate';

Note: MigrationBuilder IS a runtime export (it's a class), so it can remain a value import.

Environment

  • node-pg-migrate: 8.0.4 (latest)
  • Node.js: 22.x
  • tsx: installed as loader
  • Package type: "type": "module" (ESM)

Workaround

Use the template-file-name config option with a custom template that uses import type:

{
  "template-file-name": "database/migrations/template.ts",
  "ignore-pattern": "template\\.ts"
}

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions