How to create a course with Claude Code (and what happens next)

Published: Apr 06, 2026

https://www.teachable.com/blog/how-to-create-a-course-with-claude-code

If you are a creator with a technical itch, the pitch is almost irresistible: describe what you want, let Claude Code build it, and launch your course platform in a weekend. No monthly platform fees. No revenue share. Total control over the student experience.

That pitch is real. Claude Code genuinely can scaffold a working LMS from your terminal in hours. But working and production-ready are two different things, and most builder-educators find that out the hard way around week three.

This guide gives you the honest version. You will learn exactly how to use Claude Code to build a course platform from scratch, with real commands, real stack decisions, and real code. You will also see precisely where the complexity compounds, so you can make the right call for your business. For context on what happens when that complexity catches up with you, see our companion post: What happens when your vibe-coded course app breaks (and it will).

What Claude Code is and whether it can actually build a course platform

Claude Code is Anthropic's agentic coding tool that runs directly in your terminal. It reads your entire codebase, writes and edits files, runs commands, and debugs errors, acting as a senior pair programmer with a 200,000-token context window. Yes, it can scaffold a fully functional course platform, including auth, payments, and video delivery. Anthropic's official Claude Code in Action course, available on both Coursera and Anthropic's Skilljar platform, confirms this architecture: you are directing an autonomous agent, not copying snippets into your IDE.

For course creators with some technical confidence, this opens a genuinely exciting door. The typical stack Claude Code reaches for when you ask it to build an LMS:

  • Next.js for the frontend and API routes
  • Supabase for the Postgres database, authentication, and file storage
  • Stripe for payment processing and subscription management
  • Mux or AWS S3 + CloudFront for video hosting and delivery (more on the cost difference below)
  • Vercel for deployment

That is a legitimate production stack. Now let's build with it.

How to set up Claude Code and start building your LMS

Install Claude Code via npm: npm install -g @anthropic-ai/claude-code. Authenticate with your Anthropic API key, then run claude in your project directory. Claude Code reads your filesystem and starts scaffolding immediately.

Before generating anything, spend 15 minutes writing a CLAUDE.md file in your project root. This is your project memory. Claude Code reads it at the start of every session. Include your stack decisions, naming conventions, and any constraints:

# CLAUDE.md

## Project: WellnessLMS

### Stack
- Frontend: Next.js 14 (App Router)
- Database + Auth: Supabase
- Payments: Stripe (subscription + one-time)
- Video: Mux
- Deployment: Vercel

### Conventions
- All API routes in /app/api/
- Database types auto-generated from Supabase schema
- No hardcoded API keys — use .env.local only
- Row Level Security (RLS) must be enabled on all Supabase tables

### Business rules
- Students enroll per-course or via monthly subscription
- Certificates issue on 100% module completion
- EU customers require GDPR consent on signup

That context file is worth more than any prompt. Claude Code references it across the entire build, keeping your architecture consistent as the codebase grows.

Start the session:

$ claude

> Build the core database schema for a course platform. Courses have modules,
> modules have lessons. Students enroll in courses. Track completion per lesson.
> Use Supabase. Enable RLS on every table.

Claude Code will generate a supabase/migrations/ folder with your schema, enable RLS, and write the corresponding TypeScript types. Review the output carefully. The schema decisions it makes here will shape every query you write for the rest of the project.

How to add Stripe payments to a Claude Code-built course platform

Tell Claude Code to implement Stripe Checkout for one-time course purchases and Stripe Subscriptions for recurring access. The critical pieces are a webhook endpoint to handle payment events, a Supabase function to update enrollment status, and idempotency logic to prevent duplicate enrollments from webhook retries. Teachable's Get Started with Payments support article is worth reading to understand what a production-grade payment integration looks like in practice.

Payments are where most AI-generated LMS builds introduce their first serious technical debt. Claude Code will implement the happy path correctly, covering customer creation, checkout session, and redirect. Three things it sometimes misses unless you ask explicitly:

  • Webhook signature verification. Every incoming Stripe event must be verified with stripe.webhooks.constructEvent() using your webhook secret. Without this, any attacker can fake a payment.
  • Idempotency keys on enrollment updates. Stripe retries failed webhooks up to three times. Without idempotent logic, a student gets enrolled multiple times and your analytics break.
  • Failed payment handling. invoice.payment_failed events need to downgrade or lock access immediately, or subscribers get free access after their card declines.
// pages/api/webhooks/stripe.ts
import Stripe from 'stripe';
import { buffer } from 'micro';

export const config = { api: { bodyParser: false } };

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);

export default async function handler(req, res) {
  const buf = await buffer(req);
  const sig = req.headers['stripe-signature']!;

  let event: Stripe.Event;

  try {
    event = stripe.webhooks.constructEvent(
      buf,
      sig,
      process.env.STRIPE_WEBHOOK_SECRET!
    );
  } catch (err) {
    return res.status(400).send(`Webhook Error: ${err.message}`);
  }

  // Handle enrollment with idempotency check
  if (event.type === 'checkout.session.completed') {
    const session = event.data.object as Stripe.Checkout.Session;
    await enrollStudentIdempotent(session.client_reference_id, session.metadata.courseId);
  }

  res.json({ received: true });
}

Paste the webhook handler above into your Claude Code session and ask it to implement enrollStudentIdempotent against your Supabase schema. It will write the upsert logic correctly when the full context is available.

How to handle video hosting for a custom course platform

Use Mux for video hosting rather than self-hosting on AWS S3. Mux handles transcoding, adaptive bitrate streaming, and signed URL protection out of the box. Direct S3 hosting works initially but becomes expensive and complex to secure as your student count grows.

Claude Code will happily generate an S3 upload pipeline. Starting there is not wrong. Here is what you need to know before you ship to real students:

Raw S3 video delivery with CloudFront costs roughly $0.085 per GB transferred. A 45-minute HD lesson runs about 2 to 3 GB. If 100 students each watch it twice in a month, you are looking at $34 to $51 in bandwidth for a single lesson. Scale that across a full course library and the bill surprises people. Mux prices by the minute, not by gigabyte, which makes costs more predictable. Current rates are published on Mux's pricing page and have dropped significantly since late 2025. For a direct comparison of the two approaches, Mux's S3 cost comparison post is worth reading.

Signed URLs expire, which is the right security pattern, but you need to regenerate them on each page load or your video players break mid-session. Claude Code generates this logic correctly, but the expiry management becomes a source of ongoing bugs in production.

Ask Claude Code to scaffold the Mux integration:

> Add Mux video upload and playback to the course platform.
> Use Mux's direct upload API for instructors.
> Protect playback with signed tokens — tokens must expire after 24 hours.
> Store the Mux asset ID and playback ID in the lessons table.

How to secure student data in a Claude Code-built Supabase app

Enable Row Level Security (RLS) on every Supabase table before you write a single query. Wiz Research found that 1 in 5 vibe-coded applications have critical security misconfigurations, with disabled or overly permissive RLS policies among the most common. RLS misconfiguration in a course platform means any authenticated user can read any student's data.

The Veracode 2025 GenAI Code Security Report, which tested over 100 LLMs across 80 real coding tasks, found that AI-generated code introduces security vulnerabilities in 45% of cases. Java had the highest failure rate at over 70%. The CLAUDE.md instruction we wrote earlier -- "RLS must be enabled on all Supabase tables" -- handles this if you are consistent. Verify it manually before you launch. In Supabase Studio, check every table in the Table Editor: the RLS toggle should be green.

Your core RLS policies for a course platform look like this:

-- Students can only read their own enrollment records
create policy "Students read own enrollments"
  on enrollments for select
  using (auth.uid() = student_id);

-- Students can only read lessons in courses they're enrolled in
create policy "Students read enrolled lessons"
  on lessons for select
  using (
    exists (
      select 1 from enrollments
      where enrollments.course_id = lessons.course_id
      and enrollments.student_id = auth.uid()
      and enrollments.status = 'active'
    )
  );

-- Instructors can read and write their own courses
create policy "Instructors manage own courses"
  on courses for all
  using (auth.uid() = instructor_id);

Feed these to Claude Code and ask it to verify your entire schema has matching policies. It will flag any tables missing coverage.

What gets complicated when you run a custom course platform

The complexity that compounds as a custom LMS grows falls into four categories: video bandwidth costs, payment webhook reliability, certificate generation, and EU compliance (GDPR and VAT). Each is solvable. Each also requires weeks of engineering time that grows with your student count, not your feature list.

This is the part nobody covers in the weekend-build tutorials. You shipped. Students enrolled. Things work. Then:

  • Your AWS bill arrives. 500 active students watching 4 hours of video each month generates 2,000 hours of streaming. That number grows linearly with every student you add.
  • A webhook retry loop fills your database. Stripe retried a failed event 18 times over 72 hours. Your idempotency check had a gap. Now 14 students have duplicate enrollment records and their progress data is split across two rows.
  • A German student asks for a GDPR data export. Under GDPR, you have 30 days to respond with a complete export of all data you hold on that individual. You have no export tooling. You are writing raw SQL at midnight.
  • EU students want VAT invoices. VAT rates differ by country. You did not build VAT calculation into your Stripe integration. Every EU B2B customer is technically entitled to a proper VAT invoice.
  • A student reports that their certificate will not load. Your PDF generation library has a dependency conflict with the version of Node.js Vercel upgraded to. Certificates are broken for everyone. You spend a Saturday debugging.

None of these are insurmountable. Each one is a real engineering problem that pulls you away from creating content, building your audience, and running your education business.

When building your own LMS stops making sense

A custom Claude Code-built LMS makes sense for technical creators with highly specific requirements: unusual course structures, deep integrations with proprietary systems, or a business model that no existing platform supports. For most knowledge businesses, the maintenance overhead of a custom platform outweighs the platform fees within 6 to 12 months of launch.

The calculus is simpler than it sounds. Add up the hours you spent this month on infrastructure: debugging, updating dependencies, monitoring error logs, responding to student-reported bugs. Multiply that by your effective hourly rate. Compare that number to what a dedicated platform costs per month.

Most creator-educators who run that math end up in the same place. The platform fee is not a cost. It is a salary for a DevOps engineer who never sleeps.

If you have built your proof of concept with Claude Code and validated that students will pay, Teachable is the natural next move. You keep everything you built, your curriculum, your brand, your community relationships, and hand off the infrastructure layer entirely.

Teachable handles Stripe webhooks, video transcoding and video hosting and delivery, GDPR-compliant data management, EU VAT collection, automated certificate delivery, student progress tracking, and mobile optimization. All of it is included in your monthly plan. For a full breakdown of current plan options, see Teachable's 2025 pricing and plan updates. You stop debugging and start teaching.

The Claude Code build was not wasted. It validated your business model, sharpened your understanding of what your students need, and gave you the technical credibility to customize Teachable's integrations intelligently. Build to learn, then switch to ship.

If you are ready to stop playing DevOps and focus on what you are actually good at, start a free trial on Teachable and see how much of your week comes back.

Sign up for Teachable

Join more than 150,000 creators who use Teachable to make a real impact and earn a real income.

Your expertise has always been your edge. Let’s scale it