diff --git a/discord/README.md b/discord/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..82265e8f2159da431311275b12d9adc3cff62f89
--- /dev/null
+++ b/discord/README.md
@@ -0,0 +1,6 @@
+- Express server
+- Vanilla TRPCClient in node
+
+---
+
+Created by [@alexdotjs](https://twitter.com/alexdotjs).
diff --git a/discord/package.json b/discord/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..4cd1c47f6267eab9dca68f420eddcd04047f1ffa
--- /dev/null
+++ b/discord/package.json
@@ -0,0 +1,41 @@
+{
+  "name": "@examples/express-server",
+  "version": "10.12.0",
+  "private": true,
+  "scripts": {
+    "dev:server": "tsx watch src/server",
+    "dev:client": "wait-port 2021 && tsx watch src/client",
+    "dev": "run-p dev:* --print-label",
+    "build": "tsc",
+    "lint": "eslint --ext \".js,.ts,.tsx\" --report-unused-disable-directives src",
+    "start": "pnpm dev",
+    "test-dev": "start-server-and-test 'tsx src/server' 2021 'tsx src/client'",
+    "test-start": "start-server-and-test 'node dist/server' 2021 'node dist/client'"
+  },
+  "dependencies": {
+    "@trpc/client": "^10.12.0",
+    "@trpc/react-query": "^10.12.0",
+    "@trpc/server": "^10.12.0",
+    "@types/node-fetch": "^2.5.11",
+    "express": "^4.17.1",
+    "node-fetch": "^2.6.1",
+    "zod": "^3.0.0"
+  },
+  "alias": {
+    "scheduler/tracing": "../../node_modules/scheduler/tracing-profiling"
+  },
+  "devDependencies": {
+    "@types/express": "^4.17.12",
+    "@types/node": "^18.7.20",
+    "@types/react": "^18.0.9",
+    "eslint": "^8.30.0",
+    "npm-run-all": "^4.1.5",
+    "start-server-and-test": "^1.12.0",
+    "tsx": "^3.9.0",
+    "typescript": "^4.8.3",
+    "wait-port": "^1.0.1"
+  },
+  "publishConfig": {
+    "access": "restricted"
+  }
+}
diff --git a/discord/src/server.ts b/discord/src/server.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1a484b5113d4fb016b94fa4362e63145c48eb996
--- /dev/null
+++ b/discord/src/server.ts
@@ -0,0 +1,133 @@
+import { TRPCError, inferAsyncReturnType, initTRPC } from '@trpc/server';
+import * as trpcExpress from '@trpc/server/adapters/express';
+import { EventEmitter } from 'events';
+import express from 'express';
+import { z } from 'zod';
+
+const createContext = ({
+  req,
+  res,
+}: trpcExpress.CreateExpressContextOptions) => {
+  const getUser = () => {
+    if (req.headers.authorization !== 'secret') {
+      return null;
+    }
+    return {
+      name: 'alex',
+    };
+  };
+
+  return {
+    req,
+    res,
+    user: getUser(),
+  };
+};
+type Context = inferAsyncReturnType<typeof createContext>;
+
+const t = initTRPC.context<Context>().create();
+
+const router = t.router;
+const publicProcedure = t.procedure;
+
+// --------- create procedures etc
+
+let id = 0;
+
+const ee = new EventEmitter();
+const db = {
+  posts: [
+    {
+      id: ++id,
+      title: 'hello',
+    },
+  ],
+  messages: [createMessage('initial message')],
+};
+function createMessage(text: string) {
+  const msg = {
+    id: ++id,
+    text,
+    createdAt: Date.now(),
+    updatedAt: Date.now(),
+  };
+  ee.emit('newMessage', msg);
+  return msg;
+}
+
+const postRouter = router({
+  createPost: t.procedure
+    .input(z.object({ title: z.string() }))
+    .mutation(({ input }) => {
+      const post = {
+        id: ++id,
+        ...input,
+      };
+      db.posts.push(post);
+      return post;
+    }),
+  listPosts: publicProcedure.query(() => db.posts),
+});
+
+const messageRouter = router({
+  addMessage: publicProcedure.input(z.string()).mutation(({ input }) => {
+    const msg = createMessage(input);
+    db.messages.push(msg);
+
+    return msg;
+  }),
+  listMessages: publicProcedure.query(() => db.messages),
+});
+
+// root router to call
+const appRouter = router({
+  // merge predefined routers
+  post: postRouter,
+  message: messageRouter,
+  // or individual procedures
+  hello: publicProcedure.input(z.string().nullish()).query(({ input, ctx }) => {
+    return `hello ${input ?? ctx.user?.name ?? 'world'}`;
+  }),
+  // or inline a router
+  admin: router({
+    secret: publicProcedure.query(({ ctx }) => {
+      if (!ctx.user) {
+        throw new TRPCError({ code: 'UNAUTHORIZED' });
+      }
+      if (ctx.user?.name !== 'alex') {
+        throw new TRPCError({ code: 'FORBIDDEN' });
+      }
+      return {
+        secret: 'sauce',
+      };
+    }),
+  }),
+});
+
+export type AppRouter = typeof appRouter;
+
+async function main() {
+  // express implementation
+  const app = express();
+
+  app.use((req, _res, next) => {
+    // request logger
+    console.log('⬅️ ', req.method, req.path, req.body ?? req.query);
+
+    next();
+  });
+
+  app.use(
+    '/trpc',
+    trpcExpress.createExpressMiddleware({
+      router: appRouter,
+      createContext,
+    }),
+  );
+  app.get('/', (_req, res) => res.send('hello'));
+  app.listen(2021, () => {
+    console.log('listening on port 2021');
+  });
+}
+
+main();
diff --git a/discord/tsconfig.json b/discord/tsconfig.json
new file mode 100644
index 0000000000000000000000000000000000000000..428f2bb550af9de9d5161437382446efe95cbcf6
--- /dev/null
+++ b/discord/tsconfig.json
@@ -0,0 +1,34 @@
+{
+  "compilerOptions": {
+    "lib": ["es5", "es6", "es7", "esnext", "dom"],
+    "target": "es5",
+    "module": "commonjs",
+    "declaration": true,
+    // "moduleResolution": "node",
+    "outDir": "./dist",
+    "allowUnreachableCode": false,
+    "allowUnusedLabels": false,
+    "esModuleInterop": true,
+    "emitDecoratorMetadata": true,
+    "experimentalDecorators": true,
+    "sourceMap": true,
+    "resolveJsonModule": true,
+    /* Strict Type-Checking Options */
+    "strict": true /* Enable all strict type-checking options. */,
+    "noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */,
+    "strictNullChecks": true /* Enable strict null checks. */,
+    "noImplicitThis": true /* Raise error on 'this' expressions with an implied 'any' type. */,
+    "alwaysStrict": true /* Parse in strict mode and emit "use strict" for each source file. */,
+    // "strictPropertyInitialization": false,
+    /* Additional Checks */
+    "noUnusedLocals": true /* Report errors on unused locals. */,
+    "noUnusedParameters": true /* Report errors on unused parameters. */,
+    "noImplicitReturns": true /* Report error when not all code paths in function return a value. */,
+    "noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */
+  },
+  "include": ["src"],
+  "exclude": [
+    "node_modules"
+    // "**/__tests__/"
+  ]
+}