DEV Community

Cover image for Medusa-extender custom entity
Chris Bongers
Chris Bongers

Posted on • Originally published at


Medusa-extender custom entity

Since we moved over to the docker version of medusa, we can quickly run Postgres as our database.
With that, we can finally try out some custom entities.

In this specific article, we'll look at how it's done with medusa-extender

Generating the post module

As every new component in medusa-extender is technically a module, let's start by creating a post module with the following command.

./node_modules/.bin/medex g -m post
Enter fullscreen mode Exit fullscreen mode

We'll need an entity next, and we can use the following command for that.

./node_modules/.bin/medex g -e post
Enter fullscreen mode Exit fullscreen mode

Last but not least, we'll need a migration.

./node_modules/.bin/medex g -mi post
Enter fullscreen mode Exit fullscreen mode

Those will be the three commands needed for this article, and they should generate the following structure in your project.

Medusa module format

For the module, we don't have to change anything. However, we need to log it in our main.ts file to use it.

import { PostModule } from './modules/post/post.module';

await new Medusa(resolve(__dirname, '..'), expressInstance).load([PostModule]);
Enter fullscreen mode Exit fullscreen mode

As for the entity, open up the file and place the following code inside.

import { Column, Entity } from 'typeorm';
import { Entity as MedusaEntity } from 'medusa-extender';

export class Post {
  name: string;
Enter fullscreen mode Exit fullscreen mode

By default, medusa-extender will take care of the primary entity properties, such as the ID and the date objects.
We add a name column to this.

Now we can move to the migration file, which will be used to update our database.
We have to write this ourselves at the time of writing due to some technical constraints.

import {MigrationInterface, QueryRunner} from 'typeorm';
import {Migration} from 'medusa-extender';

export class PostMigration1663651032643 implements MigrationInterface {
    name = 'PostMigration1663651032643';

    public async up(queryRunner: QueryRunner): Promise<void> {
        await queryRunner.query(
            `CREATE TABLE IF NOT EXISTS "post" (
                "id" character varying NOT NULL,
                "name" character varying NOT NULL,
                "created_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
                "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()

    public async down(queryRunner: QueryRunner): Promise<void> {
        await queryRunner.dropTable("post", true)
Enter fullscreen mode Exit fullscreen mode

Here we create the table post in the up command with all the columns it should come with.
And in the down command, we delete it, this part is needed for when your query fails, or the user would revert the migration.

The last part is to enable the migrations for the extender. Open up your medusa-config.js file and add the following line:

module.exports = {
  projectConfig: {
    cli_migration_dirs: ['dist/**/*.migration.js'],
Enter fullscreen mode Exit fullscreen mode

Now you can open up the docker server instance and run the following commands.

// First, build everything:
npm run build

// Then run the migrations
./node_modules/.bin/medex m -r
Enter fullscreen mode Exit fullscreen mode

And that's it!
You should see the post table if you open up your database.

Post table in database

Thank you for reading, and let's connect!

Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on Facebook or Twitter

Top comments (3)

nicklasgellner profile image
Nicklas Gellner

Love that you include the extender part in your tutorial. So cool! πŸ”₯

dailydevtips1 profile image
Chris Bongers

Thanks, just another view on solving issues.
It's cool we have two kind of ways of doing things.


11 Tips That Make You a Better Typescript Programmer

1 Think in {Set}

Type is an everyday concept to programmers, but it’s surprisingly difficult to define it succinctly. I find it helpful to use Set as a conceptual model instead.

#2 Understand declared type and narrowed type

One extremely powerful typescript feature is automatic type narrowing based on control flow. This means a variable has two types associated with it at any specific point of code location: a declaration type and a narrowed type.

#3 Use discriminated union instead of optional fields


Read the whole post now!