Location: Remote
As an Engineer at Skillshare, you’ll shape how teachers share their expertise, how students discover and watch content they love, and how our platform shows up to the world. This role sits at the foundations of our backend — the domain model, the service architecture, the event backbone, and the conventions every other engineer builds on top of.
You’ll work in a single TypeScript monorepo built on hexagonal architecture, Domain-Driven Design, and Clean Architecture. Our services are NestJS, our API is code-first GraphQL, our data lives in Postgres behind Prisma, our domain events travel through a transactional outbox
into Pub / Sub, and everything runs on Cloud Run defined in Pulumi. Each bounded context is packaged as a domain core plus swappable adapters — an in-memory adapter for tests, a Prisma / Postgres adapter for persistence, provider adapters for third parties — so the domain never learns what technology is underneath it.
This is a role for someone who thinks in aggregates and boundaries, writes the decision record before the code, and leaves behind a codebase that the next engineer can navigate without a guided tour.
Your expertise:
You have 8+ years building backend systems in production, with deep TypeScript and Node.js experience and the judgement that comes from having maintained your own designs for years
You are proficient with an agentic coding harness — Claude Code, or a comparable tool — as your normal way of building software, not as occasional autocomplete. You’re comfortable with a model writing the majority of the code while you own the design, the review, and the result
You review generated code more sceptically, not less. You catch the plausible-but-wrong, notice the quietly dropped edge case or the invariant that stopped being enforced, and never let something land because it read confidently. Whoever typed it, you’re accountable for what you merge
You’ve practised Domain-Driven Design on a real, messy domain — not just read the book. You can find an aggregate boundary, defend it, and explain why a table is not an aggregate and a service is not a bounded context
You’ve built systems on hexagonal architecture / ports and adapters, you understand the dependency rule and why it points inward, and you know both the cost of that indirection and when it’s worth paying
You’re strong in NestJS — modules, providers, dependency injection, lifecycle, testing — or you’ve built and maintained production services in another Node.js backend framework (Fastify, Express, Hono, AdonisJS, tRPC) and would pick Nest up quickly. This is a Node.js and TypeScript role end to end; depth in the JVM or .NET ecosystems doesn’t substitute for it
You’ve designed and owned a GraphQL API, not just added resolvers to one: schema modelling, the N+1 problem and batching, pagination, error semantics, and evolving a live schema without breaking clients
You’ve worked in event-driven systems and can talk concretely about at-least-once delivery, idempotency, ordering, and consumer retries — and about why writing to the database and publishing to a broker in the same breath is a bug, not a shortcut
You’re fluent in relational data modelling and SQL — schema design, migrations against live data, indexing, and transaction boundaries that are chosen rather than inherited
You have strong testing instincts: you use fast in-memory implementations of your own ports for unit tests, reserve integration tests for the seams that actually integrate, and can work test-first when the design is uncertain
You communicate design clearly — in writing and visually. This role produces decision records, domain glossaries, and standards that other engineers read and follow, so arguing a technical position clearly in prose is a hard requirement, not a soft skill. The visual half matters just as much: architecture diagrams, data and event flows, and context maps are how a distributed design gets reviewed before it is built



