{"id":33108974,"url":"https://github.com/cerinoligutom/GraphQL-Starter","last_synced_at":"2025-11-15T18:01:10.489Z","repository":{"id":37175160,"uuid":"185643958","full_name":"cerinoligutom/GraphQL-Starter","owner":"cerinoligutom","description":"A boilerplate for TypeScript + Node Express + Apollo GraphQL APIs.","archived":false,"fork":false,"pushed_at":"2025-06-11T21:12:44.000Z","size":5390,"stargazers_count":111,"open_issues_count":3,"forks_count":25,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-06-20T06:52:55.389Z","etag":null,"topics":["boilerplate","boilerplate-node","boilerplate-template","docker","express","graphql","kysely","nodejs","postgresql","prisma","supertokens","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cerinoligutom.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2019-05-08T16:36:48.000Z","updated_at":"2025-06-03T21:14:00.000Z","dependencies_parsed_at":"2025-06-20T06:52:57.539Z","dependency_job_id":"dc661c60-3ffd-45bb-a2da-8ce53c0057d8","html_url":"https://github.com/cerinoligutom/GraphQL-Starter","commit_stats":null,"previous_names":["cerinoligutom/graphql-starter","cerino-ligutom/graphql-starter"],"tags_count":0,"template":true,"template_full_name":null,"purl":"pkg:github/cerinoligutom/GraphQL-Starter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cerinoligutom%2FGraphQL-Starter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cerinoligutom%2FGraphQL-Starter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cerinoligutom%2FGraphQL-Starter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cerinoligutom%2FGraphQL-Starter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cerinoligutom","download_url":"https://codeload.github.com/cerinoligutom/GraphQL-Starter/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cerinoligutom%2FGraphQL-Starter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":284597116,"owners_count":27032396,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-11-15T02:00:06.050Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["boilerplate","boilerplate-node","boilerplate-template","docker","express","graphql","kysely","nodejs","postgresql","prisma","supertokens","typescript"],"created_at":"2025-11-15T01:00:22.736Z","updated_at":"2025-11-15T18:01:10.481Z","avatar_url":"https://github.com/cerinoligutom.png","language":"TypeScript","funding_links":[],"categories":["Implementations","Examples"],"sub_categories":["JavaScript/TypeScript","TypeScript Examples"],"readme":"# TypeScript Node Express + Apollo GraphQL Starter\n\nA boilerplate for TypeScript + Node Express + Apollo GraphQL APIs.\n\n## Table of Contents\n\n- [Features](#features)\n- [Setup](#setup)\n- [Prerequisites](#prerequisites)\n- [Getting Started](#getting-started)\n- [Project Structure](#project-structure)\n- [Sample Environment File](#sample-environment-file)\n- [Recommended Workflow](#recommended-workflow)\n- [Database Migrations and Seeding](#database-migrations-and-seeding)\n- [Session Management with Supertokens](#session-management-with-supertokens)\n- [Naming Convention](#naming-convention)\n- [Deployment](#deployment)\n- [Pro Tips](#pro-tips)\n- [Contributing](#contributing)\n- [Known Dependency Issues](#known-dependency-issues)\n- [License](#license)\n\n## Features\n\n- ESM (ECMAScript Modules) support\n- Login with Email and Password\n- Session Management (Access Token + Rotating Refresh Tokens) with [SuperTokens](https://supertokens.com/).\n  - [SuperTokens](https://supertokens.com/) is only used for [Session Management](https://supertokens.com/docs/session/introduction) with this setup but it can do more than that. If you need a different kind of Authentication (e.g. Social Login, Passwordless), read more on the SuperTokens docs on how to setup one easily.\n- Node Express REST endpoint examples\n- Apollo GraphQL as middleware for Node Express\n- Centralized error handling\n  - See `src/errors/base.error.ts` and `src/errors/error-handler/index.ts`.\n  - For GraphQL, see `src/graphql/index.ts` and look for the `formatError` of Apollo.\n  - For REST, see `src/middlewares/error.middleware.ts`.\n- Automatic type code generation for GraphQL resolvers with GraphQL Code Generator\n- Facebook Dataloader for caching and batching\n- PostgreSQL Database\n- pgAdmin for managing the PostgreSQL Database\n- Redis for Caching and GraphQL Subscription\n- RedisCommander for managing the Redis Database\n- Pre-commit hook for auto formatting files with Husky, Lint-Staged and Prettier\n- Zod for schema validations\n- GraphQL Subscription example\n- Dockerized containers for both development and production\n  - Multi-stage build for production\n- Kysely for query building\n- Prisma for database migrations and seeding\n\n### Important notes\n\n- If your project has authorization needs and your frontend also uses JavaScript/TypeScript, I recommend using [CASL](https://casl.js.org/). If you want to spin your own but not sure how, here's a [good article](https://css-tricks.com/handling-user-permissions-in-javascript/) to get the ideas down. If you want a language-agnostic solution, there is [Permify](https://www.permify.co/).\n\n## Setup\n\n![architecture](https://user-images.githubusercontent.com/6721822/232209335-d9cd5b7d-a6da-4f75-9a44-f4e56848b880.png)\n\nIf the nature of your app isn't CRUDy (for a lack of a better word), you probably need domain models and a good amount of layering + mappers. Here's a [good article on the topic](https://blog.ploeh.dk/2012/02/09/IsLayeringWorththeMapping/). Otherwise, proceed.\n\n## Prerequisites\n\n- [Docker](https://www.docker.com/)\n- [NodeJS](https://nodejs.org/)\n- TypeScript\n- [supertokens-website](https://www.npmjs.com/package/supertokens-website) on your frontend app.\n  - For the client-side session management.\n  - Read more [here](https://supertokens.io/docs/session/common-customizations/sessions/cookie-consent#cookie-consent) for more info about the specific cookies being used by `SuperTokens`.\n  - If you don't use JS for your frontend app, you'll have to make the HTTP requests that `supertokens-website` heavy lifts yourself, such as [refreshing the session when it expires](https://app.swaggerhub.com/apis/supertokens/FDI).\n\n## Getting Started\n\n```bash\n# Install dependencies for the host\npnpm install\n\n# Generate GraphQL Types\npnpm generate:gql-types\n\n# Build the project for the first time or when you add dependencies\ndocker-compose build\n\n# Start the application (or to restart after making changes to the source code)\ndocker-compose up\n\n# Or run it in detached mode then listen only to this application's logs\ndocker-compose up -d\ndocker-compose logs -f api\n```\n\nThen refer to [Database Migrations and Seeding](#database-migrations-and-seeding) to setup the database.\n\n**Note:** You might be prompted to share your drive with Docker if you haven't done so previously. The drive letter you need to share in this case would be the drive letter of where this repository resides.\n\n---\n\nIf docker compose have bootstrapped all services successfully, you should be able to access:\n\n### GraphQL Endpoint\n\n[http://localhost:8080/graphql](http://localhost:8080/graphql)\n\n### pgAdmin endpoint\n\n[http://localhost:8888/](http://localhost:8888/)\n\nLogin to the pgAdmin page using the credentials below:\n\n| Field    | Value       |\n| -------- | ----------- |\n| email    | dev@app.com |\n| password | password    |\n\nIf first time setting up:\n\n- Right click on the `Servers` then create a new server.\n- In the `General` tab, give this server connection a name.\n- Switch over to the `Connection` tab.\n- Fill in the fields below.\n\n| Field             | Value    | Notes                                                                            |\n| ----------------- | -------- | -------------------------------------------------------------------------------- |\n| Host name/address | db       | Service name in `docker-compose.yml` file for our Database service is named `db` |\n| Username          | postgres | Default username is `postgres`                                                   |\n| Password          | password | As defined in the `docker-compose.yml` config                                    |\n\n### Redis Commander endpoint\n\n[http://localhost:8889](http://localhost:8889/)\n\n### Node Express REST Health Check endpoint\n\n[http://localhost:8080/api/v1/maintenance/health-check](http://localhost:8080/api/v1/maintenance/health-check)\n\n**Note:** If you prefer a different port, container name, or anything docker environment related. Just modify the `docker-compose.yml` file and adjust to your preferred setup.\n\n## Project Structure\n\n| Name                                                  | Description                                                                                 |\n| ----------------------------------------------------- | ------------------------------------------------------------------------------------------- |\n| **src/config**/\\*                                     | Any app level environment configs should go here.                                           |\n| **src/db**/schema/index.ts                            | Zod Database schemas goes here.                                                             |\n| **src/db**/types.d.ts                                 | Generated types by `prisma-kysely`.                                                         |\n| **src/errors**/`\u003cerror-name\u003e`.error.ts                | Custom Errors.                                                                              |\n| **src/generated**/\\*\\*/\\*.ts                          | Generated files.                                                                            |\n| **src/graphql**/scalars/`\u003cscalar-name\u003e`.scalar.ts     | Custom Scalars and their resolvers.                                                         |\n| **src/graphql**/enums/index.ts                        | GraphQL Enum resolvers and internal values.                                                 |\n| **src/graphql**/index.ts                              | Apollo GraphQL setup.                                                                       |\n| **src/graphql**/schema.ts                             | GraphQL Schema/Resolver builder script.                                                     |\n| **src/graphql**/init-loaders.ts                       | Collect all dataloaders here.                                                               |\n| **src/graphql**/pubsub.ts                             | Initialize pubsub engine here.                                                              |\n| **src/middlewares**/`\u003cmiddleware-name\u003e`.middleware.ts | Node Express Middleware files.                                                              |\n| **src/modules**/`\u003cmodule-name\u003e`/\\*                    | Your feature modules.                                                                       |\n| **src/modules**/\\_/\\*                                 | Reserved module. Contains root schema for graphql to work along with some sample resolvers. |\n| **src/redis**/index.ts                                | Default Redis client is initialized here along with some helpers.                           |\n| **src/shared**/                                       | Anything that's shared (generic) throughout the app should be placed here.                  |\n| **src/utils**/`\u003cutility-name\u003e`.util.ts                | Utility files.                                                                              |\n| **src/app.ts**                                        | Main application file.                                                                      |\n| .dockerignore                                         | Folder and files ignored by Docker.                                                         |\n| .eslintignore                                         | Folder and files ignored by ESLint.                                                         |\n| .eslintrc.js                                          | Linter rules are defined here.                                                              |\n| .gitignore                                            | Folder and files that should be ignored by git.                                             |\n| .huskyrc                                              | Husky config. Git hooks made easy.                                                          |\n| .lintstagedrc                                         | Lint-Staged config. Run commands against staged git files.                                  |\n| .prettierrc                                           | Prettier config. An opinionated code formatter.                                             |\n| codegen.yml                                           | GraphQL Code Generator (file watcher) config file.                                          |\n| docker-compose.yml                                    | Docker compose config file.                                                                 |\n| Dockerfile                                            | `Production` Docker config file.                                                            |\n| Dockerfile.dev                                        | `Development` Docker config file used by `docker-compose`.                                  |\n| gulpfile.ts                                           | Gulp task runner config file.                                                               |\n| tsconfig.json                                         | Contains typescript config for this project.                                                |\n\n**Note:** This project structure makes use of **barrel files**, those **index.ts** you see on most of the folders. Make sure not to forget to export your newly created files to their respective **barrel files (index.ts)** if applicable!\n\n## Sample Environment File\n\n```dotenv\n# Make sure to set this to \"production\" in production environments\nNODE_ENV=\n\n# If you want to change the app port. Defaults to 8080.\nPORT=\n\n# DB Connection URLs\nPOSTGRES_CONNECTION_URL=\nREDIS_CONNECTION_URL=\n\n# SuperTokens\nSUPERTOKENS_CONNECTION_URL=\nSUPERTOKENS_API_KEY=\nSUPERTOKENS_APP_NAME=\nSUPERTOKENS_API_DOMAIN=\nSUPERTOKENS_WEBSITE_DOMAIN=\n```\n\nSee files inside `src/config/*` that uses `process.env`. Those are the environment variables that you can configure.\n\n## Recommended Workflow\n\n### Update your database models in the Prisma Schema\n\nIf your feature requires modifications to the database, update the Prisma Schema accordingly then run `pnpm exec prisma migrate dev`.\n\nSee [docs](https://www.prisma.io/docs/concepts/components/prisma-migrate/migrate-development-production) if you're unfamiliar with this command.\n\nSince we have `prisma-kysely` configured, this should also generate the corresponding typescript types for your database models and should be usable with Kysely right away for your database queries.\n\n### (Optional) Update the seed script\n\nIf you want to seed data, update the seed file at `prisma/seed.ts` accordingly.\n\n### Create/Update the corresponding Zod schema for your database model\n\nBased on your database model changes, make sure to reflect your schema changes as well in the `src/db/schema/index.ts` file.\n\n### Create a folder for your Feature Module\n\n1. Create one under the `src/modules/\u003cmodule_name\u003e` directory.\n\n### Create a Use Case (and/or Services)\n\n1. Create a use case TS file under your module.\n   - Should be under `src/modules/\u003cmodule_name\u003e/use-cases/\u003cuse_case_name\u003e.use-case.ts`\n2. Create a Zod schema for your DTO.\n3. Infer the DTO type based on the Zod schema for your use case.\n4. Check for auth requirements if applicable.\n5. Validate DTO.\n6. Write your business logic for the use case.\n   - If some operations warrants creating a service, don't hesitate to create one.\n7. Make sure to return an object-like data on your use case functions so that you can easily extend the results if needed.\n   - Unless it's a write operation and is idempotent in nature, then you might not need to return anything.\n\n**Important:**\n\n- Your Interface Layer shouldn't do any DB Operations directly.\n- Use cases should never call another use case. There will be tight coupling if you do that. In the case you decide to change a parameter or behavior on the child use case, the dependent use case would've to adjust accordingly. Instead, create a service that both use cases can use.\n- If you foresee an operation that you think will be reused whether by the same or other modules, put it in a service and let this service be called by the module that wants to use it.\n\n### GraphQL - Create the type definitions for your entity\n\n1. Create a GraphQL file (`.graphql`) under a graphql folder of your module: `src/modules/\u003cmodule_name\u003e/graphql/`.\n   - The folder structure convention is important. This particular path is being used by GraphQL Code Generator and `graphql-tools/load-files` to locate your type definitions.\n1. Define your GraphQL SDL.\n1. Think in graphs.\n   - Your schema doesn't necessarily have to be a reflection of your database schema.\n\n### GraphQL - Create a factory for your entity type\n\n1. If not yet present, create a new folder named `factories` under `src/modules/\u003cmodule_name\u003e/`.\n1. Create a factory file under that folder.\n   - Recommended file name should be in the format: `\u003centity-name\u003e.factory.ts`\n1. Create the main factory function inside the file:\n\n   - Recommended function name should be in the format: `createGQL\u003cgraphql-object-type-name\u003e`\n   - Make sure to specify the return type of this function to the equivalent GraphQL Object Type generated by GraphQL Code Generator.\n   - Example:\n\n     ```ts\n     function createGQLUser(user: Selectable\u003cUser\u003e): GQL_User {\n       // ...\n     }\n     ```\n\n### GraphQL - Create your resolvers\n\n1. If not yet present, create a new folder named `resolvers` under `src/modules/\u003cmodule_name\u003e/graphql/`.\n1. Create an `index.ts` file under the folder.\n   - **Note:** This is important as `src/graphql/schema.ts` uses the `index` barrels (TS files) to load the resolvers.\n1. Create the `query/mutation/subscription` resolver file under the folder.\n1. Implement. Refer to the resolvers under `user` for examples.\n\n**Tip:** Keep your resolvers thin by making the business logic layer (use cases) do the actual work and calling those in the resolvers.\n\nIf you have enums defined in your GraphQL Schema, most likely you have your own internal values which means you'll have to resolve these enums to match your internal values which, most of the time, are internal enums you use in the app. Simply define the enums under the `src/graphql/enums` directory and make sure to export it on the `index` barrel.\n\nThis is also true to scalars at `src/graphql/scalars`.\n\n### REST - Define routes\n\n1. If not yet present, create a new folder named `routes` under `src/modules/\u003cmodule_name\u003e/`.\n1. Create an `index.ts` file inside that folder.\n   - **Note:** This file will contain all your route definitions (router) for that module.\n   - **Important:** Do not forget to import this router on `app.ts`.\n1. Define the router. See existing index files for examples.\n\n### REST - Define route handlers\n\n1. If not yet present, create a new folder named `handlers` under `src/modules/\u003cmodule_name\u003e/routes/`.\n1. Create a route handler file under that folder.\n   - Recommended file name should be in the format: `\u003cgraphql-object-type-name\u003e.handler.ts`\n1. Implement. Refer to the route handlers under `user` for examples.\n1. Add this route handler to your router.\n   - Make sure to wrap this with the async handler util.\n\n## Database Migrations and Seeding\n\nMigrations and Seeding is handled by Prisma. Refer to [docs](https://www.prisma.io/docs/guides/migrate/developing-with-prisma-migrate) on how to work with this.\n\nThe environment variables (see `src/config/environment.ts` file) are currently configured with consideration to a running Docker container so running the scripts below directly from the Host machine wouldn't work. As you can see from the file, the connection strings are pointing to addresses that based on the Docker containers name (defined in `docker-compose.yml`) and the default Docker Network created from running `docker-compose up` makes this work.\n\nThis means you should run the Prisma commands within the Docker container. You can do this in two simple ways, either use _(1)_ the Docker extension from VS Code or _(2)_ do it via CLI by:\n\nFirst, identify the Container ID:\n\n```bash\ndocker ps\n```\n\nThen run the following command:\n\n```bash\ndocker exec -it \u003ccontainer_id\u003e sh\n```\n\n**Tip:** You don't need to supply the entire Container ID, just the first few unique sequence. For example, your target Container ID is `dc123f66554b`. You can just run `docker-exec -it dc sh` and you'll be inside the container.\n\nOnce inside the container, you can run your prisma commands.\n\n### To create a migration and/or run migrations\n\n```bash\npnpm exec prisma migrate dev\n```\n\nThis will run database migrations. If there are changes in the Prisma Schema before you run this command, it will create a migration file and you will be prompted for a name for the migration. Make sure to double check the output.\n\n**Important:** If you're not using Docker to run this app, you need to configure the connection strings of the database servers (e.g. Redis, PostgreSQL) via the environment variables.\n\n### To seed the database\n\n```bash\npnpm exec prisma db seed\n```\n\n**Important:** Make sure to write idempotent seed scripts!\n\nResetting the database also runs the seed automatically.\n\n```bash\npnpm exec prisma migrate reset\n```\n\n## Session Management with Supertokens\n\nThis boilerplate makes use of [SuperTokens](https://supertokens.com/) to handle sessions (with cookies) because security is very hard. The folks from Supertokens know really well what they're doing and it'd be in your best interest to know how this topic should be handled properly. Here are some relevant resources:\n\n- [Stop using JWT for sessions](http://cryto.net/~joepie91/blog/2016/06/19/stop-using-jwt-for-sessions-part-2-why-your-solution-doesnt-work/)\n- [The best way to securely manage user sessions](https://supertokens.com/blog/the-best-way-to-securely-manage-user-sessions)\n- [Detecting session hijacking using rotating refresh tokens - OSW 2020](https://www.youtube.com/watch?v=6Vzit514kZY\u0026list=PLE5w09cAseKTIFCImkqFbSeYMHPzW7M_f\u0026index=18)\n\nThat said, see [SuperTokens docs for specifics](https://supertokens.com/docs/session/introduction).\n\n### Unauthenticated requests\n\nWhen trying this boilerplate and heading to the playground right away to test some GraphQL queries, you'll probably get an Unauthenticated Error. Something like the one below for example when querying `users`:\n\n```json\n{\n  \"errors\": [\n    {\n      \"message\": \"Unauthenticated. Please try logging in again.\",\n      \"locations\": [\n        {\n          \"line\": 2,\n          \"column\": 3\n        }\n      ],\n      \"path\": [\"users\"],\n      \"extensions\": {\n        \"code\": \"UNAUTHENTICATED\",\n        \"data\": {\n          \"$errorId\": \"801aecca-b19f-410c-9a7e-e9724b6f0e9f\"\n        }\n      }\n    }\n  ],\n  \"data\": null\n}\n```\n\nThis is because you're trying to request a resource that requires authentication (and in turn, you'll need a session). See this [issue](https://github.com/cerino-ligutom/GraphQL-Starter/issues/27#issuecomment-1065886375) for implementation details of this boilerplate. Basically, the idea is you need the session cookies to be attached on your requests and this can be done after logging in successfully.\n\nYou can hit the `/api/v1/auth/login/superadmin` endpoint to login as superadmin and get a session cookie to make requests on the playground. Your access token might expire after some time so you'll need to refresh it. Under normal circumstances, the frontend SDK of Supertokens will handle this for you but since we're working purely on the backend side for this boilerplate, you'll have to clear the cookies manually and then hit the endpoint again.\n\nIf sessions with cookies is not an option for you, Supertokens also supports header-based sessions (basically token-based). See [this link](https://supertokens.com/docs/session/common-customizations/sessions/token-transfer-method) for specifics. In the scenario that you're not using any of the Frontend SDK of Supertokens, then refer [here](https://supertokens.com/docs/session/quick-setup/handling-session-tokens#if-not-using-our-frontend-sdk).\n\n**Note:** If you're not using Docker to run this app or prefer using Supertokens' Managed Service, make sure to configure the environment variables. See `src/config/supertokens.ts`.\n\n## Naming Convention\n\n### For files and folders\n\nGenerally, use `snake-case`.\n\nIn most cases, we include the file `functionality` in its file name in the format:\n\n`\u003cfile-name\u003e.\u003cfunctionality\u003e.\u003cextension\u003e`\n\nFor example:\n\n- get-users`.use-case`.ts\n- sort-direction`.enum`.ts\n- user`.model`.ts\n- async-handler`.util`.ts\n\nTypeScript `Interface` and `Type` file names should match their definition name.\n\nFor example:\n\n| Interface/Type name   | File name                |\n| --------------------- | ------------------------ |\n| `IAccessTokenPayload` | `IAccessTokenPayload`.ts |\n| `IContext`            | `IContext`.ts            |\n| `UniqueID`            | `UniqueID`.ts            |\n| `Maybe`               | `Maybe`.ts               |\n\n## Deployment\n\n### **SuperTokens Core**\n\nRead more on the SuperTokens [docs based on your infrastructure](https://supertokens.com/docs/session/quick-setup/core/with-docker).\n\nMake sure to configure the [database setup](https://supertokens.com/docs/session/quick-setup/database-setup/postgresql).\n\n### **Node App**\n\nThere are a few ways to go about this and can vary based on your setup.\n\n### Docker Way\n\nSimply build the image from your local machine (or let your CI tool do it) with the command below.\n\n```bash\n# The dot on the end is important.\ndocker build -f \u003cdocker_file\u003e -t \u003cimage_name\u003e[:\u003cimage_tag\u003e] .\n\n# Example:\ndocker build -f Dockerfile -t graphql-starter:latest .\n```\n\nThen push the image you just built from your local machine (or from your CI tool) to your docker image repository (e.g. Docker Hub, AWS ECR, GitHub Container Registry).\n\n```bash\ndocker push \u003ctypically_a_url_to_your_docker_image_repository\u003e\n```\n\nLet your host server pull this image and run it from there.\n\n**Note:** Typically, the `tag` for the image you built should match the `url` to your docker image repository. Refer to your image repository provider for specific details.\n\n**Extra:** If you want to test the image you just built with your local setup, then configure the docker-compose file such that it points to your image instead of building from a Dockerfile. For example:\n\nFrom:\n\n```yaml\nservices:\n  api:\n    build:\n      context: .\n      dockerfile: Dockerfile.dev\n    command: npm start\n    volumes:\n      - .:/usr/src/app\n      - /usr/src/app/node_modules\n    restart: always\n```\n\nTo:\n\n```yaml\nservices:\n  api:\n    # Set it to the image you just built\n    image: graphql-starter:latest\n    restart: always\n```\n\n### Build Locally\n\nIf you're not using Docker, you can still get your hands on the build files. Normally, you'd want this approach if you're deploying to a VPS and have to move the files via FTP manually to your server or you have a cloud provider that accepts node apps where you'll have to provide it your project files with a `package.json` file in the project folder (typically zipped).\n\nBuild the project:\n\n```bash\npnpm build:prod\n```\n\nThis will create a `build` folder in the project directory which you can deploy.\n\n**Note:** You might need to manually install the dependencies yourself if you're using a VPS. Otherwise, your cloud provider's NodeJS container will typically just need a `package.json` from the root folder and they'll do the installation on every deploy.\n\n## Pro Tips\n\n- When resolver types are generated by GraphQL Code Generator, the type of the 1st parameter of a **field resolver** is the parent type by default. This is not always true because at runtime, what the parent resolver returns is the actual type/object that will arrive in the field resolver 1st (parent) parameter. In cases like this, you'd need to type assert the parent. See `full-name.query.ts`.\n\n  - Another example for this is let's say we have a `pets` table and a pet has an `ownerId` but in your GraphQL Schema, what you expose is `owner` and not `ownerId`. You won't have access to the `ownerId` in your resolver because GraphQL Code Generator generates what you defined in the schema. You'll have then to type assert in your resolver the type you know you returned.\n\n- If you want to rename a field in your GraphQL Schema:\n\n  - **DO NOT** rename first on the GraphQL schema file (`*.graphql`).\n    - Because if you do, the files that references the to-be-renamed field will break and TypeScript will fail to compile.\n    - GraphQL Code Generator only generates what's defined in the schema and overwrites the generated file so the old name that was previously being referenced is now missing.\n  - What you **SHOULD DO** instead is:\n    - Rename first the field in the generated graphql type definition file by GraphQL Code Generator at `src/generated/graphql/index.ts` then apply the new name in the GraphQL schema file.\n      - Saves your time and sanity.\n\n- When trying to auto import a GraphQL resolver to its respective index barrel (`index.ts` file), you might notice you're not getting code completion when typing the resolver name in the `export default` object. This is normal because your IDE thinks you're typing the key/property name (remember key-value pair).\n\n- When trying to debug async functions in VSCode and the breakpoints on the inner lines won't hit, try adding `trace: true` to `launch.json` file.\n\n- Generated custom scalars by GraphQL Code Generator are given a type of `any`. As with TypeScript, if you can help it, give it a type/interface then map it to GraphQL Code Generator. You can [read more here](https://graphql-code-generator.com/docs/plugins/typescript#scalars). But basically:\n\n  1. You define the type/interface in the corresponding scalar file and export it.\n  2. Then map it to GraphQL Code Generator by adding scalars config in `codegen.yml` such that it points to its corresponding scalar file.\n     - Format is: `\u003cScalar_Name_in_GQL_Schema\u003e: \u003cpath_to_custom_type\u003e#\u003cname_of_type\u003e`\n\n- If you're using this repo template with Docker Windows, you'll notice that when you save any file, the watchers aren't reacting. This has something to do with Linux not being able to detect file changes from Windows because the file system events are not being propagated down to Linux. You'll have to resort to polling mechanisms in that case for any tools that watches file changes. I recommend using WSL and developing inside WSL instead.\n\n- If you want to boost your knowledge about GraphQL, I highly recommend reading the e-book: [Production Ready GraphQL](https://book.productionreadygraphql.com/) by Marc-Andre Giroux.\n\n- If you have a use case for File Uploads, I recommend reading [Apollo's blog post](https://www.apollographql.com/blog/backend/file-uploads/file-upload-best-practices/) for options. There used to be a simple example in this boilerplate but has been removed. See [Issue #42](https://github.com/cerino-ligutom/GraphQL-Starter/issues/42) and the associated pull request to see relevant code.\n\n## Contributing\n\nIf something is unclear, confusing, or needs to be refactored, please let me know. Pull requests are always welcome but do consider the opinionated nature of this project. Please open an issue before submitting a pull request.\n\n## Known dependency issues\n\nIt might not look good to list it here but I think it's important for you to be aware of the issues currently being worked on (and hopefully get a fix from their respective authors/maintainers soon) as you'd still end up with these issues if you were to implement these yourself and use the same dependencies.\n\n- Wrong TypeScript types from Apollo's `graphql-subscriptions` vs `graphql-codegen`. [More info.](https://github.com/cerino-ligutom/GraphQL-Starter/issues/20#issuecomment-978072791)\n\n## License\n\nMIT License\n\nCopyright (c) 2019-Present Cerino O. Ligutom III\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcerinoligutom%2FGraphQL-Starter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcerinoligutom%2FGraphQL-Starter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcerinoligutom%2FGraphQL-Starter/lists"}