Master Fullstack Golang
Go from zero to production ready application while learning the necessary skills to work as a fullstack developer
Introduction
Gives the viewer a brief introduction to the course, what to expect and which topics we will cover.
Welcome to master fullstack golang
In this episode, you'll learn how to build a production-ready fullstack application with Golang from scratch. We'll explore modern Go tools including Temple, Goose, and SQLC, along with hypermedia libraries like HTMX and Datastar. You'll create a responsive blog with Tailwind CSS, implement authentication and middleware, and build an admin panel for content management. By the end, you'll have the skills and confidence to build and deploy professional web applications as a fully capable Go developer.
What does early access entail?
In this episode, the instructor explains that the course is in early access, meaning the overall structure is complete but some videos may contain spelling or coding errors being actively fixed. Videos are marked as "completed," "revision," or "planned" in the top right corner of the player. Viewers are encouraged to use the episode feedback button below the video player to report any unclear content, mistakes, or errors, as the instructor welcomes feedback while working to meet quality standards.
Golang Language Fundamentals
Provides the viewer with a quick walk-through of Go's syntax.
Variables, constants and functions
In this episode, we explore Go's strong typing system and how it handles variables through zero values instead of null or empty concepts. We learn about variable declarations, the difference between mutable variables and constants, and when to use the shorthand notation within functions. The episode also covers how to create and work with functions in Go, including how to accept arguments and return multiple values from a single function.
If statements and switch statements
In this episode, we explore control flow in Go programming through if-else statements and switch statements. We cover basic if-else syntax, the importance of limiting nesting to two levels for code readability, and shorthand forms for checking conditions. We also examine switch statements as an alternative to multiple if-else conditions, demonstrating how to use cases, default behavior, and the automatic break feature that prevents fall-through unless explicitly specified with the fall-through keyword.
Slices, maps and looping
In this episode, we explore Go's data structures for working with sequences of elements, including arrays (fixed size) and slices (dynamic size). We learn how slices are built on top of arrays and can grow dynamically using the append function. The episode also covers maps as key-value data structures and demonstrates various ways to loop through these collections using Go's for keyword with different syntax patterns.
Structs and interfaces
In this episode, we explore Go's approach to composition over inheritance, where structs are combined to build complex data structures like a bank system with users, accounts, and transactions. We learn how to add methods to structs, such as a withdraw function, and discover how Go's duck typing enables powerful interface-based programming. The key takeaway is that interfaces should be discovered organically as patterns emerge across different structs, rather than being created preemptively.
Packages, modules and privacy
In this episode, we explore Go's package system and visibility rules. We learn that package main with func main serves as the program's entry point, and that Go uses naming conventions rather than keywords to control access—lowercase names are private to their package while uppercase names are public. We also cover how to organize code into separate packages, import them using the module name from go.mod, and the importance of being conservative about what we expose from our packages.
Error handling and observability
In this episode, we explore Go's error handling and why the "if error != nil" pattern is actually a good thing. We learn that Go forces you to deal with errors where they occur rather than through catch-all functions, making it clear where things went wrong. The episode demonstrates how to handle errors at different layers of an application, when to log errors, and how to use tools like `errors.Is` and `errors.As` to examine specific error types and provide better feedback to both users and developers.
Go routines and channels
In this episode, I introduce Go routines and channels as Go's approach to concurrency, allowing multiple functions to make progress simultaneously. I demonstrate how to create go routines using the `go` keyword and explain how channels enable communication between go routines and the main program through blocking operations. I show a practical worker pattern example where multiple go routines can process data chunks independently, though I note that most web development tasks won't require direct use of go routines since many packages already handle concurrency under the hood.
Go's standard library
MVC & Application structure
Walks the viewer through the model-view-controller architecture and sets up the base of the application structure.
What's a model
In this episode, we explore the concept of models in Go beyond simple database table mappings, treating them as core system components that encapsulate business logic and data validation. We demonstrate how to create user and admin models with find and create functions, emphasizing that Go's type system allows us to enforce distinctions between conceptually different entities even when they might share a database table. We also clarify the difference between business logic (data shape and validation, which belongs in the model layer) and application logic (user operations and permissions, which belongs in controllers or services). Finally, we build a simple article model with dummy data to illustrate these concepts before connecting to a real database in future episodes.
What's a view
In this episode, the instructor explains how to build user interfaces for a Go web application using server-side rendering. While Go's standard html/template package works for embedding data into HTML, it lacks type safety and IDE support. To address these limitations, the instructor introduces Templ, a type-safe templating library inspired by JSX that stays entirely within Go, generating plain Go functions that return safe HTML while providing full compiler support and IDE assistance.
What's a controller
In this episode, we explore controllers as the traffic directors of a web application that receive requests, call models for data, and pass results to views. We start by building a simple controller using Go's standard library, then refactor it using the Echo framework to reduce boilerplate code. Echo provides helpful abstractions through its context object, making it easier to handle requests, extract route parameters, and manage errors, while maintaining the same fundamental pattern of receiving requests, calling models, and rendering views.
Separation of concerns
In this episode, we explore the principle of separation of concerns, which ties together the Model-View-Controller architecture. We learn that each component should have one clear responsibility: models handle data, views handle presentation, and controllers coordinate between them. This separation makes applications easier to maintain and grow, allowing us to modify one part without unintentionally breaking others. Understanding these boundaries helps us build more robust and scalable systems.
Router and routes
In this episode, we formalize URL routing by creating a dedicated routes package to centralize path definitions and avoid scattering magic strings throughout the codebase. We define routes for the homepage and article pages with dynamic ID parameters, then update the home view to reference these centralized routes using string replacement and conversion functions. Finally, we build a router package that configures Echo by registering our routes to their corresponding controllers, creating a clean structure that we can expand as our application grows.
Laying the foundations
In this episode, we lay the foundations of the application architecture by exploring the Model-View-Controller (MVC) pattern and how to adapt it for Go. We discuss the three core components—Models for data and business logic, Views for presentation, and Controllers for coordinating requests—and why MVC emphasizes separation of concerns, making code predictable, testable, and maintainable. We then scaffold the base project structure by creating folders for models, views, controllers, commands, routes, and config, setting up a clean foundation for building a real-world Go application in upcoming episodes.
Configuration and secrets
In this episode, we set up environment-based configuration for our application using environmental variables and Go structs. We create a config package that reads values like app host, port, environment, and project name from a .env file, using struct tags and the env package to parse them automatically. We also establish global constants for development and production environments, add a method to generate TCP addresses from our config, and prepare our application to handle different settings across development, testing, and production environments without hardcoding values.
Testable entrypoint
In this episode, we create the application entry point by setting up a main.go file in the CMD directory with a main function and a testable run function. We configure an HTTP server with the router, set timeouts, and successfully start the application on localhost:8080, confirming that our blog is working by viewing sample articles in the browser. However, we still need to set up a proper Postgres database before we can build out the full application functionality.
Postgres & database fundamentals
This module introduces PostgreSQL and database fundamentals to the viewer.
Options for installation
In this episode, you'll learn how to set up Postgres as your database for the course using two approaches: installing it directly on your system or running it in a Docker container. The tutorial covers creating Postgres roles and databases, understanding how Postgres authentication works with system users, and demonstrates both installation methods step-by-step. Docker is recommended for easier development setup, while direct installation is preferred for production environments.
Relational database concepts
In this episode, we cover the fundamentals of relational databases, explaining how they store structured data in tables with rows and columns. We explore primary keys for unique identification, foreign keys for connecting tables, and the different types of relationships like one-to-one, one-to-many, and many-to-many. We also discuss normalization for organizing data efficiently and introduce SQL as the language used to define, insert, and query data across related tables.
ACID and data integrity
In this episode, we explore how transactions and ACID properties ensure data integrity in relational databases. We learn that transactions are units of work that either completely succeed or fail, preventing partial updates that could corrupt data. The four ACID guarantees—Atomicity, Consistency, Isolation, and Durability—work together to keep data safe and reliable, even when multiple operations happen simultaneously. Using examples like flight bookings and money transfers, we see why these properties are critical for systems handling important data, and how databases like Postgres implement them through explicit transaction controls.
What about nosql?
In this episode, we explore NoSQL databases like MongoDB and Cassandra, understanding when they're useful for flexibility and scaling versus traditional relational databases. While NoSQL offers performance benefits, it comes with trade-offs like weaker consistency and missing relational features. We discuss why Postgres is the best choice for our project, as it combines relational reliability with NoSQL flexibility through JSON support, giving us the best of both worlds.
A database package
In this episode, we create a database package for our Go application that handles the connection to Postgres. We build a psql struct with a connection pool using pgxpool, which efficiently manages database connections by keeping them open and ready to use instead of constantly opening and closing them. We set up a NewPSQL function that takes a context and database URI from our config, establishes the connection pool, and returns the struct. Finally, we wire this into main.go to ensure a database connection is established when the application starts, preparing it for future queries and data operations.
Developer Experience
Focuses on setting up a nice developer environment for building fullstack apps.
Our toolbox
In this episode, we explore Go 1.24's tool directive feature, which allows adding development tools to go.mod with specific versions instead of installing them globally. We add four essential tools to the project: Templ for templating, Goose for database migrations, sqlc for generating type-safe Go code from SQL queries, and Air for hot reloading during development. This approach ensures all team members use the same tool versions and makes the development workflow more consistent across the team.
Justfile
In this episode, we introduce Justfiles as a modern alternative to Makefiles that simplifies running verbose commands for tools like Goose and SQLC. We walk through the project's Justfile, explaining how it automatically loads environment variables, provides convenient aliases for database migrations and query compilation, and uses Air to watch for file changes and auto-reload the application. The parallel command runs both view compilation and the app server simultaneously, making development much more efficient. With the Justfile configured, we now have everything needed to start building out the actual application.
Building the home view
We build the html structure for the home view while getting a firmer handle on templ.
Building the article view
We build the html structure for the article view and starts breaking code into components.
Making things pretty and responsive
We setup tailwind, talk about responsive design and make the blog presentable to real readers.
Creating and managing articles
We build out a simple admin where we can manage the articles of the blog.
Authentication and authorization
This module teaches you authentication, best practices and shows you how to roll your own auth. Completely Safe.
Modern hypermedia
Introduces the viewer to htmx and datastar, discusses "modern" frontend frameworks and adds interactivity to the blog and admin.
Preparing for production
We cover seo optimizations, caching views and static assets as well as error pages and logging strategy so we safely can go to production.
Setting up a secure VPS
In this module we cover how to configure a virtual private server so that it's secure, talk DNS and how to reverse proxy using Caddy.
Deploying a binary
We go through how to setup a database on the VPS and then deploy the binary version of our blog.
Deploying a docker image
We cover how to host our application using docker instead of systemd and setting up traefik as our reverse proxy.