Repository: echobind/bisonapp
Pull request #142 (2021-05-11 16:22:21)

feat: expose common scalars from graphql-scalars
This exposes the most commonly used ones.

Example usage: 

```ts
t.email('emailField')
t.phone('phoneField')
```

## Changes

- adds email, phone, url scalars. 


## Screenshots

n/a

## Checklist

- [ ] Requires dependency update?
- [ ] Generating a new app works

Fixes #xxx


cball: Fixes #141 

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2cc9e2c..2a96be6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,15 @@
 All notable changes to this project will be documented in this file.
 See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
 
+## 1.10.0-canary.6 (2021-05-11)
+
+
+### Features
+
+* migrate away from prisma-nexus-plugin. ([#137](https://github.com/echobind/bisonapp/issues/137)) ([093e8c4](https://github.com/echobind/bisonapp/commit/093e8c4812907cbd3a2554e0253d212610824c10))
+
+
+
 ## 1.10.0-canary.5 (2021-05-11)
 
 **Note:** Version bump only for package root
diff --git a/lerna.json b/lerna.json
index 90b57ff..ff3a2c9 100644
--- a/lerna.json
+++ b/lerna.json
@@ -1,5 +1,5 @@
 {
-  "version": "1.10.0-canary.5",
+  "version": "1.10.0-canary.6",
   "npmClient": "yarn",
   "useWorkspaces": true,
   "packages": [
diff --git a/packages/create-bison-app/CHANGELOG.md b/packages/create-bison-app/CHANGELOG.md
index fd732df..6e39078 100644
--- a/packages/create-bison-app/CHANGELOG.md
+++ b/packages/create-bison-app/CHANGELOG.md
@@ -3,6 +3,15 @@
 All notable changes to this project will be documented in this file.
 See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
 
+## 1.10.0-canary.6 (2021-05-11)
+
+
+### Features
+
+* migrate away from prisma-nexus-plugin. ([#137](https://github.com/echobind/bisonapp/issues/137)) ([093e8c4](https://github.com/echobind/bisonapp/commit/093e8c4812907cbd3a2554e0253d212610824c10))
+
+
+
 ## 1.10.0-canary.5 (2021-05-11)
 
 **Note:** Version bump only for package create-bison-app
diff --git a/packages/create-bison-app/package.json b/packages/create-bison-app/package.json
index a6c3617..38e2651 100644
--- a/packages/create-bison-app/package.json
+++ b/packages/create-bison-app/package.json
@@ -1,6 +1,6 @@
 {
   "name": "create-bison-app",
-  "version": "1.10.0-canary.5",
+  "version": "1.10.0-canary.6",
   "description": "Creates a production-ready full-stack Jamstack app",
   "license": "MIT",
   "repository": "echobind/bisonapp",
diff --git a/packages/create-bison-app/tasks/copyFiles.js b/packages/create-bison-app/tasks/copyFiles.js
index 3181b9a..61211ac 100644
--- a/packages/create-bison-app/tasks/copyFiles.js
+++ b/packages/create-bison-app/tasks/copyFiles.js
@@ -38,6 +38,12 @@ async function copyFiles({ variables, targetFolder }) {
     copyWithTemplate(fromPath("README.md.ejs"), toPath("README.md"), variables),
     copyWithTemplate(fromPath("_.gitignore"), toPath(".gitignore"), variables),
 
+    copyWithTemplate(
+      fromPath("_.env.ejs"),
+      toPath(".env"),
+      variables
+    ),
+
     copyWithTemplate(
       fromPath("_.env.local.ejs"),
       toPath(".env.local"),
@@ -80,7 +86,6 @@ async function copyFiles({ variables, targetFolder }) {
         "layouts",
         "lib",
         "prisma",
-        "!prisma/_.env*",
         "public",
         "scripts",
         "services",
diff --git a/packages/create-bison-app/template/prisma/_.env.ejs b/packages/create-bison-app/template/_.env.ejs
similarity index 100%
rename from packages/create-bison-app/template/prisma/_.env.ejs
rename to packages/create-bison-app/template/_.env.ejs
diff --git a/packages/create-bison-app/template/_.gitignore b/packages/create-bison-app/template/_.gitignore
index 60ade8c..eef14bb 100644
--- a/packages/create-bison-app/template/_.gitignore
+++ b/packages/create-bison-app/template/_.gitignore
@@ -26,12 +26,13 @@ npm-debug.log*
 yarn-debug.log*
 yarn-error.log*
 
+.env
+
 # local env files
 .env.local
 .env.development.local
 .env.test.local
 .env.production.local
-prisma/.env
 
 .vercel
 
diff --git a/packages/create-bison-app/template/_templates/graphql/new/graphql.ejs b/packages/create-bison-app/template/_templates/graphql/new/graphql.ejs
index 5bb213e..b606263 100644
--- a/packages/create-bison-app/template/_templates/graphql/new/graphql.ejs
+++ b/packages/create-bison-app/template/_templates/graphql/new/graphql.ejs
@@ -3,7 +3,8 @@ to: graphql/modules/<%= name %>.ts
 ---
 <% camelized = h.inflection.camelize(name) -%>
 <% plural = h.inflection.pluralize(camelized) -%>
-import { objectType, extendType } from 'nexus';
+import { objectType, extendType, inputObjectType, stringArg, arg, nonNull, enumType } from 'nexus';
+import { Role } from '@prisma/client';
 import { UserInputError, /*ForbiddenError*/ } from 'apollo-server-micro';
 
 // import { isAdmin } from '../services/permissions';
@@ -13,47 +14,34 @@ export const <%= camelized %> = objectType({
   name: '<%= camelized %>',
   description: 'A <%= camelized %>',
   definition(t) {
-    t.model.id();
-    t.model.createdAt();
-    t.model.updatedAt();
+    t.nonNull.id('id');
+    t.nonNull.date('createdAt');
+    t.nonNull.date('updatedAt');
   },
 });
 
-/*
-// Enums
-export const CallPreference = enumType({
-  name: 'CallPreference',
-  members: ['WEEKDAY', 'WEEKEND', 'WEEKNIGHT'],
-});
-
 // Queries
 export const <%= camelized %>Queries = extendType({
   type: 'Query',
   definition: (t) => {
-    // List <%= plural %> Query (admin only)
-    t.crud.<%= plural.toLowerCase() %>({
-      filtering: true,
-      ordering: true,
-      // use resolve for permission checks or to remove fields
-      resolve: async (root, args, ctx, info, originalResolve) => {
-        if (!isAdmin(ctx.user)) throw new ForbiddenError('Unauthorized');
+    // List <%= plural %> Query
+    t.list.field('<%= plural.toLowerCase() %>', {
+      type: '<%= camelized %>',
+      authorize: (_root, _args, ctx) => !!ctx.user,
+      args: nonNull(arg({ type: 'SomethingQueryInput' })),
+      description: 'Returns available <%= plural.toLowerCase() %>',
+    })
 
-        return await originalResolve(root, args, ctx, info);
+    // single query
+    t.field('something', {
+      type: '<%= camelized %>',
+      description: 'Returns a specific <%= camelized %>',
+      authorize: (_root, _args, ctx) => !!ctx.user,
+      args: nonNull(arg({ type: 'SomethingQueryInput' })),
+      resolve: (_root, args, ctx) => {
+        // TODO
       },
     });
-
-    // Custom Query
-    t.field('me', {
-      type: 'User',
-      description: 'Returns the currently logged in user',
-      nullable: true,
-      resolve: (_root, _args, ctx) => ctx.user,
-    });
-
-    t.list.field('availabilityForUser', {
-      type: 'Event',
-      description: 'Returns available time slots to schedule calls with an expert',
-    })
   },
 });
 
@@ -61,6 +49,60 @@ export const <%= camelized %>Queries = extendType({
 export const <%= camelized %>Mutations = extendType({
   type: 'Mutation',
   definition: (t) => {
+    t.field('somethingMutation', {
+      type: 'String',
+      description: 'Does something',
+      args: {
+        data: nonNull(arg({ type: 'SomethingMutationInput' })),
+      },
+      authorize: (_root, _args, ctx) => !!ctx.user,
+      resolve: async (_root, args, ctx) => {
+        console.log(args.data.hello)
+        return args.data.hello
+      }
+    });
   },
 });
-*/
\ No newline at end of file
+
+// Inputs
+export const SomethingMutationInput = inputObjectType({
+  name: 'SomethingMutationInput',
+  description: 'Input used to do something',
+  definition: (t) => {
+    t.nonNull.string('hello');
+  },
+})
+
+export const SomethingQueryInput = inputObjectType({
+  name: 'SomethingQueryInput',
+  description: 'Input used to do something',
+  definition: (t) => {
+    t.nonNull.string('hello');
+  },
+});
+
+export const <%= camelized %>OrderByInput = inputObjectType({
+  name: '<%= camelized %>OrderByInput',
+  description: 'Order <%= camelized.toLowerCase() %> by a specific field',
+  definition(t) {
+    t.field('hello', { type: 'SortOrder' });
+  },
+});
+
+export const UserWhereUniqueInput = inputObjectType({
+  name: 'UserWhereUniqueInput',
+  description: 'Input to find users based on unique fields',
+  definition(t) {
+    t.id('id');
+    t.email('email');
+  },
+});
+
+export const UserWhereInput = inputObjectType({
+  name: 'UserWhereInput',
+  description: 'Input to find users based other fields',
+  definition(t) {
+    t.int('id');
+    t.field('email', { type: 'StringFilter' });
+  },
+});
\ No newline at end of file
diff --git a/packages/create-bison-app/template/graphql/modules/index.ts b/packages/create-bison-app/template/graphql/modules/index.ts
index 1d151a8..899cb19 100644
--- a/packages/create-bison-app/template/graphql/modules/index.ts
+++ b/packages/create-bison-app/template/graphql/modules/index.ts
@@ -1,3 +1,4 @@
 export * from './scalars';
 export * from './user';
 export * from './profile';
+export * from './shared'
diff --git a/packages/create-bison-app/template/graphql/modules/profile.ts b/packages/create-bison-app/template/graphql/modules/profile.ts
index 0ef5a5b..16bcc58 100644
--- a/packages/create-bison-app/template/graphql/modules/profile.ts
+++ b/packages/create-bison-app/template/graphql/modules/profile.ts
@@ -5,15 +5,21 @@ export const Profile = objectType({
   name: 'Profile',
   description: 'A User Profile',
   definition(t) {
-    t.model.id();
-    t.model.firstName();
-    t.model.lastName();
-    t.model.createdAt();
-    t.model.updatedAt();
-    t.model.user();
+    t.nonNull.id('id');
+    t.nonNull.date('createdAt');
+    t.nonNull.date('updatedAt');
+    t.nonNull.string('firstName');
+    t.nonNull.string('lastName');
+    t.nonNull.field('user', {
+      type: 'User',
+      resolve: (parent, _, context) => {
+        return context.prisma.profile.findUnique({
+          where: { id: parent.id }
+        }).user()
+      }
+    })
 
     t.string('fullName', {
-      nullable: true,
       description: 'The first and last name of a user',
       resolve({ firstName, lastName }) {
         return [firstName, lastName].filter((n) => Boolean(n)).join(' ');
diff --git a/packages/create-bison-app/template/graphql/modules/scalars.ts b/packages/create-bison-app/template/graphql/modules/scalars.ts
index 225d499..130831a 100644
--- a/packages/create-bison-app/template/graphql/modules/scalars.ts
+++ b/packages/create-bison-app/template/graphql/modules/scalars.ts
@@ -1,5 +1,14 @@
-import { DateTimeResolver, JSONObjectResolver } from 'graphql-scalars';
+import {
+  DateTimeResolver,
+  EmailAddressResolver,
+  JSONObjectResolver,
+  PhoneNumberResolver,
+  URLResolver,
+} from 'graphql-scalars';
 import { asNexusMethod } from 'nexus';
 
-export const jsonScalar = asNexusMethod(JSONObjectResolver, 'json');
-export const dateTimeScalar = asNexusMethod(DateTimeResolver, 'date');
+export const JSON = asNexusMethod(JSONObjectResolver, 'json');
+export const DateTime = asNexusMethod(DateTimeResolver, 'date');
+export const Email = asNexusMethod(EmailAddressResolver, 'email');
+export const PhoneNumber = asNexusMethod(PhoneNumberResolver, 'phone');
+export const URL = asNexusMethod(URLResolver, 'url');
diff --git a/packages/create-bison-app/template/graphql/modules/shared.ts b/packages/create-bison-app/template/graphql/modules/shared.ts
new file mode 100644
index 0000000..0e274cb
--- /dev/null
+++ b/packages/create-bison-app/template/graphql/modules/shared.ts
@@ -0,0 +1,25 @@
+import { enumType, inputObjectType } from 'nexus';
+
+// the following items are migrated from the prisma plugin
+export const SortOrder = enumType({
+  name: 'SortOrder',
+  description: 'Sort direction for filtering queries (ascending or descending)',
+  members: ['asc', 'desc'],
+});
+
+export const StringFilter = inputObjectType({
+  name: 'StringFilter',
+  description: 'A way to filter string fields. Meant to pass to prisma where clause',
+  definition(t) {
+    t.string('contains');
+    t.string('endsWith');
+    t.string('equals');
+    t.string('gt');
+    t.string('gte');
+    t.list.nonNull.string('in');
+    t.string('lt');
+    t.string('lte');
+    t.list.nonNull.string('notIn');
+    t.string('startsWith');
+  },
+});
diff --git a/packages/create-bison-app/template/graphql/modules/user.ts.ejs b/packages/create-bison-app/template/graphql/modules/user.ts.ejs
index 2178cfe..77891f4 100644
--- a/packages/create-bison-app/template/graphql/modules/user.ts.ejs
+++ b/packages/create-bison-app/template/graphql/modules/user.ts.ejs
@@ -1,11 +1,6 @@
-import { objectType, extendType, inputObjectType, stringArg, arg } from 'nexus';
+import { objectType, extendType, inputObjectType, stringArg, arg, nonNull, enumType } from 'nexus';
 import { Role } from '@prisma/client';
-<% if (host.name === 'vercel') { -%>
 import { UserInputError, ForbiddenError } from 'apollo-server-micro';
-<% } -%>
-<% if (host.name === 'heroku') { -%>
-import { UserInputError, ForbiddenError } from 'apollo-server-express';
-<% } -%>
 
 import { hashPassword, appJwtForUser, comparePasswords } from '../../services/auth';
 import { isAdmin, canAccess } from '../../services/permissions';
@@ -15,18 +10,24 @@ export const User = objectType({
   name: 'User',
   description: 'A User',
   definition(t) {
-    t.model.id();
-    t.model.email();
-    t.model.roles();
-    t.model.createdAt();
-    t.model.updatedAt();
-    t.model.profile();
+    t.nonNull.id('id');
+    t.nonNull.date('createdAt');
+    t.nonNull.date('updatedAt');
+    t.nonNull.list.nonNull.field('roles', { type: 'Role' });
 
     // Show email as null for unauthorized users
     t.string('email', {
-      nullable: true,
       resolve: (profile, _args, ctx) => (canAccess(profile, ctx) ? profile.email : null),
     });
+
+    t.field('profile', {
+      type: 'Profile',
+      resolve: (parent, _, context) => {
+        return context.prisma.user.findUnique({
+          where: { id: parent.id }
+        }).profile()
+      }
+    })
   },
 });
 
@@ -50,23 +51,8 @@ export const UserQueries = extendType({
     t.field('me', {
       type: 'User',
       description: 'Returns the currently logged in user',
-      nullable: true,
       resolve: (_root, _args, ctx) => ctx.user,
     });
-
-    // List Users Query (admin only)
-    t.crud.users({
-      filtering: true,
-      ordering: true,
-      resolve: async (root, args, ctx, info, originalResolve) => {
-        if (!isAdmin(ctx.user)) throw new ForbiddenError('Unauthorized');
-
-        return await originalResolve(root, args, ctx, info);
-      },
-    });
-
-    // User Query
-    t.crud.user();
   },
 });
 
@@ -79,8 +65,8 @@ export const Mutations = extendType({
       type: 'AuthPayload',
       description: 'Login to an existing account',
       args: {
-        email: stringArg({ required: true }),
-        password: stringArg({ required: true }),
+        email: nonNull(stringArg()),
+        password: nonNull(stringArg()),
       },
       resolve: async (_root, args, ctx) => {
         const { email, password } = args;
@@ -109,42 +95,15 @@ export const Mutations = extendType({
       },
     });
 
-    // User Create (admin only)
-    t.crud.createOneUser({
-      alias: 'createUser',
-      resolve: async (root, args, ctx, info, originalResolve) => {
-        if (!isAdmin(ctx.user)) {
-          throw new ForbiddenError('Not authorized');
-        }
-
-        const user = await ctx.db.user.findUnique({ where: { email: args.data.email } });
-
-        if (user) {
-          throw new UserInputError('Email already exists.', {
-            invalidArgs: { email: 'already exists' },
-          });
-        }
-
-        // force role to user and hash the password
-        const updatedArgs = {
-          data: {
-            ...args.data,
-            password: hashPassword(args.data.password),
-          },
-        };
-
-        return originalResolve(root, updatedArgs, ctx, info);
-      },
-    });
-
     t.field('signup', {
       type: 'AuthPayload',
       description: 'Signup for an account',
       args: {
-        data: arg({ type: 'SignupInput', required: true }),
+        data: nonNull(arg({ type: 'SignupInput' })),
       },
       resolve: async (_root, args, ctx) => {
-        const existingUser = await ctx.db.user.findUnique({ where: { email: args.data.email } });
+        const { data } = args;
+        const existingUser = await ctx.db.user.findUnique({ where: { email: data.email } });
 
         if (existingUser) {
           throw new UserInputError('Email already exists.', {
@@ -155,9 +114,9 @@ export const Mutations = extendType({
         // force role to user and hash the password
         const updatedArgs = {
           data: {
-            ...args.data,
+            ...data,
             roles: { set: [Role.USER] },
-            password: hashPassword(args.data.password),
+            password: hashPassword(data.password),
           },
         };
 
@@ -173,11 +132,46 @@ export const Mutations = extendType({
   },
 });
 
+// Inputs
 export const SignupInput = inputObjectType({
   name: 'SignupInput',
+  description: 'Input required for a user to signup',
   definition: (t) => {
-    t.string('email', { required: true });
-    t.string('password', { required: true });
-    t.field('profile', { type: 'ProfileCreateNestedOneWithoutUserInput' });
+    t.nonNull.string('email');
+    t.nonNull.string('password');
+  },
+});
+
+// Manually added types that were previously in the prisma plugin
+export const UserRole = enumType({
+  name: 'Role',
+  members: Object.values(Role),
+});
+
+export const UserOrderByInput = inputObjectType({
+  name: 'UserOrderByInput',
+  description: 'Order users by a specific field',
+  definition(t) {
+    t.field('email', { type: 'SortOrder' });
+    t.field('createdAt', { type: 'SortOrder' });
+    t.field('updatedAt', { type: 'SortOrder' });
   },
 });
+
+export const UserWhereUniqueInput = inputObjectType({
+  name: 'UserWhereUniqueInput',
+  description: 'Input to find users based on unique fields',
+  definition(t) {
+    t.id('id');
+    t.string('email');
+  },
+});
+
+export const UserWhereInput = inputObjectType({
+  name: 'UserWhereInput',
+  description: 'Input to find users based other fields',
+  definition(t) {
+    t.int('id');
+    t.field('email', { type: 'StringFilter' });
+  },
+});
\ No newline at end of file
diff --git a/packages/create-bison-app/template/graphql/schema.ts b/packages/create-bison-app/template/graphql/schema.ts
index 90e1532..022b36c 100644
--- a/packages/create-bison-app/template/graphql/schema.ts
+++ b/packages/create-bison-app/template/graphql/schema.ts
@@ -1,7 +1,6 @@
 import path from 'path';
 
 import { declarativeWrappingPlugin, fieldAuthorizePlugin, makeSchema } from 'nexus';
-import { nexusPrisma } from 'nexus-plugin-prisma';
 
 import prettierConfig from '../prettier.config';
 
@@ -11,32 +10,20 @@ const currentDirectory = process.cwd();
 
 export const schema = makeSchema({
   types,
-  plugins: [
-    fieldAuthorizePlugin(),
-    declarativeWrappingPlugin(),
-    nexusPrisma({
-      experimentalCRUD: true,
-      outputs: {
-        typegen: path.join(
-          currentDirectory,
-          'node_modules/@types/typegen-nexus-plugin-prisma/index.d.ts'
-        ),
-      },
-    }),
-  ],
+  plugins: [fieldAuthorizePlugin(), declarativeWrappingPlugin()],
   outputs: {
     schema: path.join(currentDirectory, 'api.graphql'),
-    typegen: path.join(currentDirectory, 'node_modules/@types/nexus-typegen/index.d.ts'),
+    typegen: path.join(currentDirectory, 'types', 'nexus.d.ts'),
+  },
+  contextType: {
+    module: path.join(currentDirectory, 'graphql', 'context.ts'),
+    export: 'Context',
   },
   sourceTypes: {
     modules: [
       {
-        module: path.join(currentDirectory, 'node_modules/.prisma/client/index.d.ts'),
-        alias: 'db',
-      },
-      {
-        module: path.join(currentDirectory, 'graphql', 'context.ts'),
-        alias: 'ContextModule',
+        module: '.prisma/client',
+        alias: 'PrismaClient',
       },
     ],
   },
diff --git a/packages/create-bison-app/template/package.json.ejs b/packages/create-bison-app/template/package.json.ejs
index e65d7dd..2ad8219 100644
--- a/packages/create-bison-app/template/package.json.ejs
+++ b/packages/create-bison-app/template/package.json.ejs
@@ -12,11 +12,12 @@
     "build:nexus": "NODE_ENV=development ts-node -P tsconfig.cjs.json --transpile-only graphql/schema.ts",
     "cypress:open": "cypress open",
     "cypress:run": "cypress run",
-    "db:migrate": "yarn -s prisma migrate dev && yarn build:prisma",
-    "db:deploy": "yarn -s prisma migrate deploy && yarn build:prisma",
-    "db:reset": "yarn prisma migrate reset && yarn build:prisma",
-    "db:setup": "yarn db:migrate && yarn prisma generate",
-    "db:drop": "DOTENV_CONFIG_PATH=./prisma/.env ts-node -r dotenv/config ./scripts/dropDatabase",
+    "db:migrate": "prisma migrate dev",
+    "db:migrate:prod": "prisma migrate deploy",
+    "db:deploy": "prisma deploy",
+    "db:reset": "prisma migrate reset",
+    "db:seed": "prisma db seed --preview-feature",
+    "db:setup": "yarn db:reset",
     "dev": "concurrently -n \"WATCHERS,NEXT\" -c \"black.bgYellow.dim,black.bgCyan.dim\" \"yarn watch:all\" \"next dev\"",
     "dev:typecheck": "tsc --noEmit",
     "g:cell": "hygen cell new --name",
@@ -45,7 +46,7 @@
     "@apollo/client": "^3.0.2",
     "@chakra-ui/react": "1.3.4",
     "@chakra-ui/theme": "1.7.1",
-    "@prisma/client": "^2.19.0",
+    "@prisma/client": "^2.22.1",
     "apollo-server-micro": "^2.18.1",
     "bcryptjs": "^2.4.3",
     "cross-fetch": "3.0.5",
@@ -58,7 +59,6 @@
     "jsonwebtoken": "^8.5.1",
     "next": "9.5.3",
     "nexus": "^1.0.0",
-    "nexus-plugin-prisma": "^0.33.0",
     "react": "16.13.1",
     "react-dom": "16.13.1",
     "react-hook-form": "^6.1.0",
@@ -99,7 +99,7 @@
     "nanoid": "^3.1.10",
     "pg": "^8.3.0",
     "prettier": "^2.0.5",
-    "prisma": "^2.19.0",
+    "prisma": "^2.22.1",
     "start-server-and-test": "^1.11.2",
     "supertest": "^4.0.2",
     "ts-jest": "^26.1.3",
diff --git a/packages/create-bison-app/template/prisma/seed.ts b/packages/create-bison-app/template/prisma/seed.ts
new file mode 100644
index 0000000..7e3c3c3
--- /dev/null
+++ b/packages/create-bison-app/template/prisma/seed.ts
@@ -0,0 +1,13 @@
+import { PrismaClient } from '@prisma/client';
+const prisma = new PrismaClient();
+
+async function main() {
+  // TODO: seeds
+  console.log('no seeds yet!');
+}
+
+main()
+  .catch((e) => console.error(e))
+  .finally(async () => {
+    await prisma.$disconnect();
+  });
diff --git a/packages/create-bison-app/template/prisma/seeds.js b/packages/create-bison-app/template/prisma/seeds.js
deleted file mode 100644
index d35e2fc..0000000
--- a/packages/create-bison-app/template/prisma/seeds.js
+++ /dev/null
@@ -1,26 +0,0 @@
-/* eslint-disable no-console */
-const { PrismaClient } = require('@prisma/client');
-const dotenv = require('dotenv');
-
-dotenv.config();
-const db = new PrismaClient();
-
-async function main() {
-  // Seed data is database data that needs to exist for your app to run.
-  // Ideally this file should be idempotent: running it multiple times
-  // will result in the same database state (usually by checking for the
-  // existence of a record before trying to create it). For example:
-  //
-  //   const existing = await db.user.findMany({ where: { email: 'admin@email.com' }})
-  //   if (!existing.length) {
-  //     await db.user.create({ data: { name: 'Admin', email: 'admin@email.com' }})
-  //   }
-
-  console.info('No data to seed. See prisma/seeds.js for info.');
-}
-
-main()
-  .catch((e) => console.error(e))
-  .finally(async () => {
-    await db.$disconnect();
-  });
diff --git a/packages/create-bison-app/template/scripts/buildProd.ts b/packages/create-bison-app/template/scripts/buildProd.ts
index cb0d9c4..077410d 100644
--- a/packages/create-bison-app/template/scripts/buildProd.ts
+++ b/packages/create-bison-app/template/scripts/buildProd.ts
@@ -1,7 +1,6 @@
 export {};
 const spawn = require('child_process').spawn;
 
-const bisonConfig = require('../package.json').bison;
 const DEFAULT_BUILD_COMMAND = `yarn build:nexus && yarn build:prisma && yarn build:next`;
 
 /**
@@ -9,22 +8,11 @@ const DEFAULT_BUILD_COMMAND = `yarn build:nexus && yarn build:prisma && yarn bui
  * if the current branch should be migrated, it runs migrations first.
  */
 function buildProd() {
-  const { staging, production } = bisonConfig.branches;
-  const branchesToMigrate = new RegExp(`${staging}|${production}`);
-  const currentBranch = process.env.BRANCH || process.env.VERCEL_GITHUB_COMMIT_REF;
-  const shouldMigrate = branchesToMigrate.test(currentBranch);
-
-  console.log('--------------------------------------------------------------');
-  console.log('Determining if we should migrate the database...');
-  console.log('branches to migrate:', branchesToMigrate);
-  console.log('current branch name:', currentBranch || '(unknown)');
-  console.log(shouldMigrate ? `${currentBranch} detected. Migrating.` : `Not running migrations.`);
-  console.log('--------------------------------------------------------------');
-
   let buildCommand = DEFAULT_BUILD_COMMAND;
+  const shouldMigrate = process.env.NODE_ENV === 'production';
 
   if (shouldMigrate) {
-    buildCommand = `yarn db:migrate && ${buildCommand}`;
+    buildCommand = `yarn db:deploy && ${buildCommand}`;
   }
 
   const child = spawn(buildCommand, {


Test patch:
diff --git a/packages/create-bison-app/cypress/integration/createBisonAppWithDefaults.test.js b/packages/create-bison-app/cypress/integration/createBisonAppWithDefaults.test.js
index ae12c9f..3d2ec52 100644
--- a/packages/create-bison-app/cypress/integration/createBisonAppWithDefaults.test.js
+++ b/packages/create-bison-app/cypress/integration/createBisonAppWithDefaults.test.js
@@ -14,7 +14,7 @@ describe("Creating a new app", () => {
   describe("prisma .env", () => {
     it("contains the proper database URL", () => {
       cy.task("getAppName").then((appName) => {
-        cy.task("readProjectFile", "prisma/.env")
+        cy.task("readProjectFile", ".env")
           .should("contain", `postgresql://postgres@localhost:5432`)
           .should("contain", `${appName}_dev`);
       });
diff --git a/packages/create-bison-app/test/tasks/copyFiles.test.js b/packages/create-bison-app/test/tasks/copyFiles.test.js
index fe8fb72..e4c7122 100644
--- a/packages/create-bison-app/test/tasks/copyFiles.test.js
+++ b/packages/create-bison-app/test/tasks/copyFiles.test.js
@@ -132,7 +132,7 @@ describe("copyFiles", () => {
     });
 
     it("copies the prisma folder", async () => {
-      const files = ["migrations", "schema.prisma", "seeds.js"];
+      const files = ["migrations", "schema.prisma", "seed.ts"];
 
       files.forEach((file) => {
         const filePath = path.join(targetFolder, "prisma", file);
@@ -141,8 +141,8 @@ describe("copyFiles", () => {
       });
     });
 
-    it("copies prisma/env with the correct contents", async () => {
-      const target = path.join(targetFolder, "prisma", ".env");
+    it("copies env with the correct contents", async () => {
+      const target = path.join(targetFolder, ".env");
       const file = await fs.promises.readFile(target);
       const fileString = file.toString();
       const { user, password, host, port, name } = variables.db.dev;