'TypeORM Entity in NESTJS - Cannot use import statement outside a module
Started new project with 'nest new' command. Works fine until I add entity file to it.
Got following error:
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
^^^^^^
SyntaxError: Cannot use import statement outside a module
What do I miss?
Adding Entity to Module:
import { Module } from '@nestjs/common';
import { BooksController } from './books.controller';
import { BooksService } from './books.service';
import { BookEntity } from './book.entity';
import { TypeOrmModule } from '@nestjs/typeorm';
@Module({
imports: [TypeOrmModule.forFeature([BookEntity])],
controllers: [BooksController],
providers: [BooksService],
})
export class BooksModule {}
app.module.ts:
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Connection } from 'typeorm';
import { BooksModule } from './books/books.module';
@Module({
imports: [TypeOrmModule.forRoot()],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Solution 1:[1]
My assumption is that you have a TypeormModule
configuration with an entities
property that looks like this:
entities: ['src/**/*.entity.{ts,js}']
or like
entities: ['../**/*.entity.{ts,js}']
The error you are getting is because you are attempting to import a ts
file in a js
context. So long as you aren't using webpack you can use this instead so that you get the correct files
entities: [join(__dirname, '**', '*.entity.{ts,js}')]
where join
is imported from the path
module. Now __dirname
will resolve to src
or dist
and then find the expected ts
or js
file respectively. let me know if there is still an issue going on.
EDIT 1/10/2020
The above assumes the configuration is done is a javascript compatible file (.js
or in the TypeormModule.forRoot()
passed parameters). If you are using an ormconfig.json
instead, you should use
entities: ["dist/**/*.entity.js"]
so that you are using the compiled js files and have no chance to use the ts files in your code.
Solution 2:[2]
In the TypeORM documentation, i found a specific section for Typescript.
This section says:
Install ts-node globally:
npm install -g ts-node
Add typeorm command under scripts section in package.json
"scripts" { ... "typeorm": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js" }
Then you may run the command like this:
npm run typeorm migration:run
If you need to pass parameter with dash to npm script, you will need to add them after --. For example, if you need to generate, the command is like this:
npm run typeorm migration:generate -- -n migrationNameHere
This works with my file config:
{
"type": "postgres",
"host": "yourhost",
"port": 5423,
"username": "username",
"password": "password",
"database": "your_db",
"synchronize": true,
"entities": [
"src/modules/**/*.entity.{ts,js}"
],
"migrations": [
"src/migrations/**/*.{ts,js}"
],
"cli": {
"entitiesDir": "src/modules",
"migrationsDir": "src/migrations"
}
}
Then you can run the generate command.
Solution 3:[3]
As Jay McDoniel explained in his answer, the problem seems to be the pattern matching of entity files in ormconfig.json
file: Probably a typescript file (module) is imported from a javascript file (presumably a previously transpiled typescript file).
It should be sufficient to remove an existing ts
glob pattern in the ormconfig.json
, so that TypeORM will only load javascript files. The path to the entity files should be relative to the working directory where node is executed.
"entities" : [
"dist/entity/**/*.js"
],
"migrations" : [
"dist/migration/**/*.js"
],
"subscribers": [
"dist/subscriber/**/*.js"
],
Solution 4:[4]
I changed in tsconfig.json file next:
"module": "es6"
To:
"module": "commonjs",
It helps me
Solution 5:[5]
Defining the entities property in ormconfig.json
as mentioned in the official documentation resolved this issue for me.
// This is your ormconfig.json file
...
"entities": ["dist/**/*.entity{.ts,.js}"]
...
Solution 6:[6]
This is how I've manage to fix it. With a single configuration file I can run the migrations on application boostrap or using TypeOrm's CLI.
src/config/ormconfig.ts
import parseBoolean from '@eturino/ts-parse-boolean';
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
import * as dotenv from 'dotenv';
import { join } from 'path';
dotenv.config();
export = [
{
//name: 'default',
type: 'mssql',
host: process.env.DEFAULT_DB_HOST,
username: process.env.DEFAULT_DB_USERNAME,
password: process.env.DEFAULT_DB_PASSWORD,
database: process.env.DEFAULT_DB_NAME,
options: {
instanceName: process.env.DEFAULT_DB_INSTANCE,
enableArithAbort: false,
},
logging: parseBoolean(process.env.DEFAULT_DB_LOGGING),
dropSchema: false,
synchronize: false,
migrationsRun: parseBoolean(process.env.DEFAULT_DB_RUN_MIGRATIONS),
migrations: [join(__dirname, '..', 'model/migration/*.{ts,js}')],
cli: {
migrationsDir: 'src/model/migration',
},
entities: [
join(__dirname, '..', 'model/entity/default/**/*.entity.{ts,js}'),
],
} as TypeOrmModuleOptions,
{
name: 'other',
type: 'mssql',
host: process.env.OTHER_DB_HOST,
username: process.env.OTHER_DB_USERNAME,
password: process.env.OTHER_DB_PASSWORD,
database: process.env.OTHER_DB_NAME,
options: {
instanceName: process.env.OTHER_DB_INSTANCE,
enableArithAbort: false,
},
logging: parseBoolean(process.env.OTHER_DB_LOGGING),
dropSchema: false,
synchronize: false,
migrationsRun: false,
entities: [],
} as TypeOrmModuleOptions,
];
src/app.module.ts
import configuration from '@config/configuration';
import validationSchema from '@config/validation';
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { LoggerService } from '@shared/logger/logger.service';
import { UsersModule } from '@user/user.module';
import { AppController } from './app.controller';
import ormconfig = require('./config/ormconfig'); //path mapping doesn't work here
@Module({
imports: [
ConfigModule.forRoot({
cache: true,
isGlobal: true,
validationSchema: validationSchema,
load: [configuration],
}),
TypeOrmModule.forRoot(ormconfig[0]), //default
TypeOrmModule.forRoot(ormconfig[1]), //other db
LoggerService,
UsersModule,
],
controllers: [AppController],
})
export class AppModule {}
package.json
"scripts": {
...
"typeorm": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js --config ./src/config/ormconfig.ts",
"typeorm:migration:generate": "npm run typeorm -- migration:generate -n",
"typeorm:migration:run": "npm run typeorm -- migration:run"
},
Project structure
src/
??? app.controller.ts
??? app.module.ts
??? config
? ??? configuration.ts
? ??? ormconfig.ts
? ??? validation.ts
??? main.ts
??? model
? ??? entity
? ??? migration
? ??? repository
??? route
? ??? user
??? shared
??? logger
Solution 7:[7]
I was using Node.js with Typescript and TypeORM when I faced this issue. Configuring in ormconfig.json file worked for me.
entities: ['dist/**/*.entity.js']
My full code of ormconfig.json file:
{
"type": "mysql",
"host": "localhost",
"port": 3306,
"username": "xxxxxxxx",
"password": "xxxxxxxx",
"database": "typescript_orm",
"synchronize": true,
"logging": false,
"migrationTableName": "migrations",
"entities": [
"dist/**/*.entity.js"
],
"migrations": [
"src/migration/**/*.{ts, js}"
],
"suscribers": [
"src/suscriber/**/*.{ts, js}"
],
"cli": {
"entitiesDir": "src/model",
"migrationDir": "src/migration",
"suscribersDir": "src/suscriber"
}
}
Solution 8:[8]
Actually, typeorm was designed to work with javascript by default.
To run the migrations with typescript, you must tell typeorm to do it.
Just put in your package.json, in the scripts part this line below:
"typeorm": "ts-node-dev ./node_modules/typeorm/cli.js"
and then, try to migrate again:
yarn typeorm migration:run
Solution 9:[9]
In line with other people's comments - it does in fact seem silly to have to depend on generated code for this to work. I do not take credit for this solution as it's someone else's repository, but it does in fact allow full Typescript only migrations. It relies on the .env
file Typeorm values instead of ormconfig.json
although I'm sure it could be translated. I found it instrumental in helping me remove the dependency on .js
files.
Here is the repo: https://github.com/mthomps4/next-now-test/tree/next-typeorm-example
Explanation as to how it's working:
Aside from your usual .env or ormconfig.json file with the proper localhost db connection in it, you also need to specify the following properly in ormconfig.json or .env file
TYPEORM_ENTITIES="entities/*.ts"
TYPEORM_MIGRATIONS="migrations/*.ts"
TYPEORM_ENTITIES_DIR="entities"
TYPEORM_MIGRATIONS_DIR="migrations"
Notice the entities and migrations globs only have *.ts
. The other very important piece is how your npm scripts are setup to run with ts-node
.
You need an extended tsconfig that has the following in it somewhere:
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "commonjs"
}
}
This is what allows ts-node to "pick up" the .ts files properly while generating a migration.
This npm script (the DOTENV part is only if using .env files instead of ormconfig.json
) specifies to use that tsconfig.json
"local": "DOTENV_CONFIG_PATH=./.env ts-node -P ./tsconfig.yarn.json -r dotenv/config"
Which is leveraged as a "pre-cursor" script to this:
"typeorm:local": "yarn local ./node_modules/typeorm/cli.js"
I'm not 100% sure all of that is necessary (you may could do it all inline) but it works for me. Basically this says "invoke the typrorm cli in the context of ts-node with a specific .env file and a specific tsconfig." You may be able to skip those configurations in some cases.
Lastly, this script now works:
"g:migration": "yarn typeorm:local migration:generate -n"
So by running:
npm run g:migration -- User
You will get your automatically generated migration file based on your current changed entities!
So 3 nested npm scripts later, we have a very specific way to run the "generate" migration conmmand with all the proper configuration to use only TS files. Yay - no wonder some people still rail against typescript but thankfully this does work and the example repo above has it all preconfigured if you want to try it out to see how it "just works".
Solution 10:[10]
Also check out your imports in the entities. Don't import { SomeClassFromTypeorm } from 'typeorm/browser';
since this can lead to the same error.
It happened to me after my IDE automatically imported the wrong package. Delete '/browser'
from the import.
Solution 11:[11]
You need to have a something.module.ts for every section of your app. It works like Angular. This is setup with GraphQL resolvers and service. REST is a bit different with a controller. Each module will probably have an entity and if GraphQL, projects.schema.graphql.
projects.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ProjectsService } from './projects.service';
import { Projects } from './projects.entity';
import { ProjectsResolvers } from './projects.resolvers';
@Module({
imports: [
TypeOrmModule.forFeature([Projects])],
providers: [
ProjectsService,
ProjectsResolvers
],
})
export class ProjectsModule {}
Solution 12:[12]
This worked for me - no changes needed to your ormconfig.js
. Run from your root directory where the node_modules
are:
ts-node ./node_modules/typeorm/cli.js migration:generate -n <MirgrationName> -c <ConnectionType>
Example:
ts-node ./node_modules/typeorm/cli.js migration:create -n AuthorHasMultipleBooks -c development
Solution 13:[13]
Configuration to support migrations:
// FILE: src/config/ormconfig.ts
const connectionOptions: ConnectionOptions = {
// Other configs here
// My ormconfig isn't in root folder
entities: [`${__dirname}/../**/*.entity.{ts,js}`],
synchronize: false,
dropSchema: false,
migrationsRun: false,
migrations: [getMigrationDirectory()],
cli: {
migrationsDir: 'src/migrations',
}
}
function getMigrationDirectory() {
const directory = process.env.NODE_ENV === 'migration' ? 'src' : `${__dirname}`;
return `${directory}/migrations/**/*{.ts,.js}`;
}
export = connectionOptions;
// FILE package.json
{
// Other configs here
"scripts": {
"typeorm": "NODE_ENV=migration ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js --config src/config/database.ts",
"typeorm:migrate": "npm run typeorm migration:generate -- -n",
"typeorm:run": "npm run typeorm migration:run",
"typeorm:revert": "npm run typeorm migration:revert"
}
}
Solution 14:[14]
I think a better solution, than the accepted one, is to create a alias in your shell of choice, that uses ts-node
inside node_modules
.
Note: I'm doing this in bash, with OhMyZsh, so your configuration might be totally different.
1: Open shell configuration
Open shell configuration1
nano ~/.zshrc
2: Find the place where other aliases are defined and add a new alias
alias typeorm="ts-node ./node_modules/typeorm/cli.js"
3: Close and save
Press CTRL + X to request nano to exit and press Y to confirm to save the configuration.
4: Apply the new configuration
. ~/.zshrc
5: Close terminal and open it again
You can now go to your project root and type "typeorm" which will use ts-node in conjunction with the typeorm-cli from your node_modules.
Solution 15:[15]
I solved the problem!
Create
pm2.config.js
file in root with below codes:module.exports = { apps: [ { name: "app", script: "./build/index.js", }, ], };
Change entity path in
ormconfig.js
{ "type": "postgres", "host": "localhost", "port": 5432, "username": "postgres", "password": "password", "database": "db_name", "synchronize": false, "logging": true, "entities": [ "../src/entity/**/*.ts", ===>>> this line is important "./build/entity/**/*.js" ], "migrations": [ "../src/migration/**/*.ts",===>>> this line is important "./build/migration/**/*.js" ], "subscribers": [ "../src/subscriber/**/*.ts",===>>> this line is important "./build/subscriber/**/*.js" ], "cli": { "entitiesDir": "src/entity", "migrationsDir": "src/migration", "subscribersDir": "src/subscriber" } }
tsconfig.json
with below code:{ "compilerOptions": { "lib": [ "es5", "es6" ], "target": "es5", "module": "commonjs", "moduleResolution": "node", "outDir": "./build", "emitDecoratorMetadata": true, "experimentalDecorators": true, "sourceMap": true, "esModuleInterop": true } }
Run below command for production:
tsc =>> This command generate "build" folder
Run below command for run node app in
pm2
:tsc && pm2 start pm2.config.js
Now after 2 days with this solution my app with node express & typeorm is worked! Also my app are working on linux & nginx with pm2.
Solution 16:[16]
If you are writing in typescript and use tsc
to create a dist folder with translated js files in it, then you probably have my issue and it will get fixed here.
As it is mentioned here in the docs if you use nodemon server.js
, then you will hit the entities from js perspective and it will not recognize import as it is ts and es6 related. However if you want to import entities from ts files, you should run ts-node server.ts
!
Personally I believe the former node server.js
is a safer one to do as it is closer to the real case application.
!!! HOWEVER !!! Be very careful as you have to delete the dist folder and rebuild it if you change an entity's name, otherwise it will throw an error or work unexpectedly.
The error happens because the tsc
will try to translate the changed and created ts files and leave the deleted files so it can run faster!
I hope it helped as it will definitely help me in the future as I am almost certain I will forget about it again!
Solution 17:[17]
I have encountered the same problem. The only difference is that my project uses .env file instead of ormconfig.json
This is what my .env file configuration looks like.
TYPEORM_ENTITIES = src/modules/*.entity.ts
TYPEORM_MIGRATIONS = src/migrations/*.entity.ts
TYPEORM_MIGRATIONS_RUN = src/migrations
TYPEORM_ENTITIES_DIR = src/modules
TYPEORM_MIGRATIONS_DIR = src/migrations
And run by using command
nest start
The problem appears to be that TypeORM does not accept entities in the form of typescript files.
There are two approaches that can be used to solve this problem.
Use
node-ts
instead ofnest start
solved the problem without modifying the path of the entities file. From my understanding, node-ts will process the typescript file in the src folder without issue.Change the entity and migration file paths to point to the compiled js file in the dist folder instead.
TYPEORM_ENTITIES = dist/modules/*.entity.js TYPEORM_MIGRATIONS = dist/migrations/*.entity.js TYPEORM_MIGRATIONS_RUN = dist/migrations TYPEORM_ENTITIES_DIR = dist/modules TYPEORM_MIGRATIONS_DIR = dist/migrations
with this approach, I can use
nest start
without any problem.
Solution 18:[18]
I used this solution only for production.
for development I change "../src/entity/**/*.ts"
to "src/entity/**/*.ts"
and then run this command: "nodemon --exec ts-node ./src/index.ts"
and it works –
Solution 19:[19]
The accepted answer here (https://stackoverflow.com/a/59607836/2040160) was help me generate and run the migrations, but not to run the NestJS project. I got the same error as the author when I npm run start:dev
.
What worked for me, is to just generate the migrations file in vanilla JavaScript.
My ormconfig,json
file:
{
"type": "cockroachdb",
"host": "localhost",
"port": 26257,
"username": "root",
"password": "",
"database": "test",
"entities": ["dist/**/*.entity{.ts,.js}"],
"migrations": ["migration/*.js"],
"synchronize": false,
"cli": {
"migrationsDir": "migration"
}
}
The script in package.json
:
"typeorm": "node --require ts-node/register ./node_modules/typeorm/cli.js"
And the command I use to generate the migrations:
npm run typeorm migration:generate -- -o -n init
The -o
flag will output the migrations in vanilla JavaScript.
Solution 20:[20]
The error is on your ormconfig.json file. check where is your code searching for the entities, migrations, subscribers. In a dev, test environment it will search for them in your src/entities src/migrations src/subscribers. But in a production environment, if you leave it as it is, it will still search in the same path instead of your build path dist/src/entities etc.... ;)
Solution 21:[21]
I ran into this error trying to run typeorm migration:generate
from a project created with the TypeORM starter kit (npx typeorm init
). The issue came down to this bit that it inserted into package.json
:
"scripts": {
"typeorm": "typeorm-ts-node-commonjs"
}
Change that to:
"scripts": {
"typeorm": "typeorm-ts-node-esm"
}
And you should be good to go:
npm run -- typeorm migration:generate --dataSource path/to/data-source.ts NameOfMigration
Solution 22:[22]
npm run typeorm migration:generate -- -n translationLength
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow