Using MVC to Structure Go Web Applications
Tags: go, webdev
Published: 2019-10-22 16:59:45

---
title: Using MVC to Structure Go Web Applications
published: true
description: MVC is a well-known way to structure web applications, but it is often shunned in Go. In this article we explore how MVC can be effectively implement in Go as well as how to avoid all of the issues that many people associate with MVC.
tags: golang, go, webdev
canonical_url: https://www.calhoun.io/using-mvc-to-structure-go-web-applications/
series: Structuring Web Applications in Go
---


> *This article is part of a [larger series on Go application structure](https://www.calhoun.io/structuring-web-applications-in-go/) that was originally posted on [calhoun.io](https://www.calhoun.io/using-mvc-to-structure-go-web-applications/), where I write about Go, web dev, testing, and more. I will be porting the entire series over to Dev.to, but I appreciate you checking out on my website anyway 😀*


## What is MVC?

As you learn to program, you will eventually start to notice that some code bases are easy to navigate while others are confusing and hard to maintain or update. At first it is hard to tell what makes the difference, but over time you will quickly learn that the biggest factor is how well organized and structured the code is.

The reason for this is simple - if you need to jump in and start adding a new feature, fixing a bug, or doing anything else to a program it is much easier to do if you can guess where in the code you need to start looking. When you have no idea where to even start, you are left digging through hundreds of source files, but in a well structured program you can often guess where the code is even if you haven’t read the source code in the past.

Model-View-Controller, commonly referred to as MVC, is a pattern used to help organize and structure code. Specifically, most code will be classified as a model, view, or controller.

### Views

Views are responsible for rendering data. That’s it. Given a specific page that we want to render, and data for that page, our view is responsible for generating the correct output. If we are implementing an application using MVC, this will typically be server-rendered HTML that we want to return to the end user’s browser, but it doesn't have to be. Our view could just as easily handle rendering XML, JSON, or other data types.

The important thing to remember is that the code in a view should have as little logic going on as possible; instead, it should focus entirely on displaying data. If logic starts to creep into your views you are likely doing something wrong, and it could become problematic down the road.

In my applications I like to have some global helper functions available in all templates that aren't provided by the `html/template` package. For instance, it is very common to want to render the current user's avatar or email address in the navbar, but providing this data in every single template render can be tedious. Or I may want helpers for rendering HTML forms via Go structs using something like my [form](https://github.com/joncalhoun/form) package. None of these extra functions are a requirement of a `view` package, but I find them helpful when thinking about what my view is providing.


### Controllers

Air traffic controllers are the people that inform each plane at an airport where to fly, when to land, and on which runway to land. They don’t actually do any piloting, but instead are in charge of telling everyone what to do so that an airport can operate smoothly.

Controllers in MVC are very similar to air traffic controllers. They won't be directly responsible for writing to a database or creating HTML responses, but instead they will direct incoming data to the appropriate models, views, and other packages that can be used to complete the work requested.

Similar to views, a controller shouldn’t be packed with too much business logic. Instead, they should mostly just parse data and ship it off to other functions, types, etc to handle.


### Models

Models are the final part of MVC, and their primary responsibility is interacting with your application's data. This typically means communicating with your database, but it could also mean interacting with data that comes from other services or APIs. It might also mean validating or normalizing data.

A quick example - most web applications will have some notion of a user who signs up and interacts with the web application in some way. In an MVC application we might create a `type User struct {...}` in the models package that represents a user stored in our database. We might then create some code to help us validate that a user is valid and some additional code to help us create, update, and query for users in our database.

One important distinction that I'd like to make here is that I consider the `models` package to encompass database interactions. As we dive into some potential problems with MVC, we will look at how not doing this can lead to some potential problems.


## MVC can be implemented in a variety of ways

When we talk about MVC it is important to note that MVC doesn't have a single specific implementation. It is a general architectural pattern, not a specific set of rules we must follow. As a result, two developers using MVC might end up with very different structures.

Part of this is because there are really two aspects of an app's structure that we need to consider:

1. How we organize code into types/funcs.
2. How we package up those types/funcs.

While MVC definitely gives us guidance on how to organize our code into types/functions, it doesn't necessarily dictate that we package our code into `models`, `views`, and `controllers` directories. As a result, I would consider the following two examples to both use MVC.

### Example 1: Packaging our code based on it's layer

```bash
app/
  models/
    user.go
    course.go
  controllers/
    user.go
    course.go
  views/
    user.go
    course.go
```

In this first example we are organizing our code into packages based on its "layer" - or in other words, we package all the views together, all the controllers together, and so on. This is by far the most common layout you will see with MVC.


### Example 2: packaging our code based on the resource

```bash
app/
  user/
    controller.go
    model.go
    store.go
    view.go
  course/
    controller.go
    model.go
    store.go
    view.go
```

In the second example we are opting to package our code based on the resource, and then inside of each package we have our model, view, and controller. This is less common for an MVC application, but I would still consider it to be MVC.


*Sidenote: I consider both `model.go` and `store.go` to be the "models" part of MVC in this example.*


Using that same line of reasoning, it is possible to use a [flat structure](https://www.calhoun.io/flat-application-structure/) and MVC at the same time.


## Why do people like MVC?

People don't like seeing 30+ source files in a single directory/package. It just feels cluttered, regardless of whether or not the files are all separated in a logical way or not. I'm not really sure why this is the case, but developers just want to start adding subdirectories and "organizing" their code.

Without a deep understanding of what you are building, it can be challenging to break your application up into logical packages. While MVC itself doesn't provide a specific solution to this problem, MVC does provide us with an initial set of layers to start with. If we opt to organize our code into packages based on these layers (*see Ex1 above*) we can start with the `models`, `views`, and `controllers` directories without really having a deep understanding of what we are building. In other words, it allows us to pick a structure right away rather than waiting for one to evolve, and many developers don't like waiting.

MVC is also appealing because it is familiar. Change can often be confusing, so when coming to Go from Django, Rails, ASP.NET, and countless other languages/frameworks that use MVC it feels comfortable to dive into something familiar. We already understand how that code is organized, so doing something similar with our Go application allows us to make one less decision, and [decision fatigue](https://en.wikipedia.org/wiki/Decision_fatigue) is a real thing.

Lastly, MVC is a pretty natural evolution from a flat-structured application where we often break our code into a database, handler, and rendering layer anyway. All three of these map pretty nicely to models, controllers, and views. More on this later.



## Using MVC effectively

Contrary to what you may read on Reddit, MVC can be used quite effectively in Go. Frameworks like [Buffalo](https://gobuffalo.io/en/docs/getting-started/directory-structure/) take advantage of the MVC structure, and I have successfully built several applications using the MVC pattern.


### Not everything is a model, view, or controller

The first key to using MVC with Go is to remember that not everything has to be a model, view, or controller. Yes, these categorizations are great starting points and will help minimize your decision making, but many parts of your application will not fall into any of these categories and that is okay.

For instance, in my course [Web Development with Go](https://www.usegolang.com/) we use the MVC pattern because I find it to be a very useful learning tool (more on that later), but it doesn't take very long before we start introducing additional packages. One example is `middleware` that are related to handling HTTP requests, but don't really fit into the `controller` package. When this occurs, it is okay to create additional packages in your codebase.

### Don't break things up too much

The second key to using MVC is to avoid breaking things up too much for no real reason. I have seen a few people try to implement MVC this way:

```bash
app/
  models/
    lesson/
      models.go
      store.go
    course/
      models.go
      store.go
  # and so on...
```

The problem with this structure is that models tend to be relational; that is, a `Course` may have many `Lesson`s, so we might want to write queries that return a course along with all of its lessons, and in the structure I just showed this typically requires additional types (like a `CourseLesson`) to avoid cyclical dependencies.

I have heard of developers having success with this pattern, so I'm not suggesting that it should never be used, but I personally haven't found it to fit my needs very well. As a result, it just isn't what I do.

*If you happen to have examples of where this pattern works well feel free to send them to me - <jon@calhoun.io>*

More generally speaking, if you find yourself with cyclical dependencies there is a good chance you either broke things up a bit too much or put a type/interface/func in the wrong place. Take [Kat Zien's layered example](https://github.com/katzien/go-structure-examples/tree/master/layered) from her talk, [How do you structure your Go apps](https://www.youtube.com/watch?v=oL6JBUk6tj0); in this example the code won't compile because the `storage` package and the `models` package have cyclical dependencies. While this seems to point with an issue in the application structure, I would actually argue that the `models` and `storage` package in this example should really be one package because they both pertain to storage. The `models` in this case just happen to be definitions of the types stored in said storage.


*To be very clear - I am in no way criticizing Kat's ability to structure applications. I believe she created this cyclical dependency intentionally to make a point in her talk, and it serves as a great example for me as well. Oh and you should totally go check out her talk if you haven't already! 👉 [Kat's Talk on YouTube](https://www.youtube.com/watch?v=oL6JBUk6tj0)*


### How should I structure my MVC apps?

Whether I am using MVC, Domain Driven Design (DDD), or another design pattern, I almost always prefer to package my code by the layer that it serves in my architecture. That is basically just a fancy way of saying I like to put all of my database code together in one package, my middleware in one package, my handlers in one package, and so on.


*Sidenote: There are definitely times where packaging code in another way makes sense, so don't take this to mean you should always package by layer. This is just what tends to work well for me.*


In MVC, that looks basically identical to what you would probably expect in an MVC application:

```bash
app/
  models/
    # user.go has all my database logic including:
    #   User - the model definition
    #   UserStore - used to perform user-related CRUD
    #     operations on the DB
    user.go
    course.go
  controllers/
    user.go
    course.go
  views/
    template.go # used to parse gohtml templates
    show_user.gohtml
    new_user.gohtml
    # ...
```

The only real caveat is that you don't really need to name these folders `models`, `controllers`, and `views`. You can, and that is perfectly fine by me if it makes development easier on you in any way, but you can also name these in a slightly more specific way. For instance, if our models are all stored in a PostgreSQL database, our controllers are all intended to handle HTTP requests, and our views are all used to render HTML, we might end up with packages like this:

```bash
app/
  psql/ # models
  http/ #controllers
  html/ #views
```

Now it is a little more clear that the `psql.User` represents a user in our Postgres database, and an `http.UserHandler` is pretty obviously a handler for http requests pertaining to users.

That doesn't mean you always have to do this. There are times when I have felt that a `models` package makes more sense. For instance, if I know my application is going to be fairly small and one of my models will be a file stored on disk (eg an image), I might opt to name my package `models` and mix-n-match all of my database and local storage code into that one package.

On the other hand, you could opt to break these two things into separate packages where one is `psql` specific, and the other is named `localdisk` or something like that.

I don't see a lot of value in criticizing someone's choice here because which decision is best almost always depends on the size and complexity of the application. What is more important to me is that you understand the tradeoffs you are making and are okay with them.

Lastly, it is worth mentioning that sometimes the reason for a package name is entirely unrelated to development/code. For instance, I prefer keeping the `models` package name in my web development course because this often makes it easier for people to grasp how we are separating our code, and thus makes it easier for them to pick up Go.


### What goes in the `models` / `sql` package?

Models is probably the most important package to get right, so we are going to start with it. For simplicity's sake, let's assume that only means SQL database interactions.

The `models` package should contain pretty much all of your code related to your data storage. That includes database-specific models, validations, normalizations, etc. It is also worth recognizing that this package shouldn't generally be importing other packages in your application. As with all rules, there are exceptions, but I find that the `models` package works best if you could literally pull it out of your application and use it in another application (say a CLI) without changing any of the code in the `models` package. In this sense, all of your models code ends up being isolated and is limited to ONLY interacting with database entities. This will make it basically impossible to introduce cyclical dependencies because your `models` package doesn't know anything about the rest of your application.

Here are a few examples of logic I might expect to find in a models package:

1. Code that defines the `User` type as it is stored in the database.
2. Logic that will check a user's email address when a new user is being created to verify that it isn't already taken.
3. If your particular SQL variant is case sensitive, code that will convert a user's email address to lowercase before it is inserted into the DB.
4. Code for inserting users into the users table in the DB.
5. Code that retrieves relational data; eg a `User` along with all of their `Reviews`.

What I wouldn't expect to find in a `models` package is code specific to rendering your HTML responses. Eg I wouldn't expect it to return errors with HTTP status codes. You *can* return an error like `NotFound` but the controller should be free to interpret and render that as it sees fit. In the context of HTTP that might end up being an `http.StatusNotFound` status code, but in the context of a CLI it could be entirely different.


### What goes in the `views` package?

This one tends to be the least code because it is usaully either:

- A glorified wrapper around the `html/template.Template` package
- A wrapper (or direct use of) the `encoding/json` package

The main way I tend to customize this is by adding a bunch of `template.FuncMap` functions to the template BEFORE parsing it (so it parses correctly), and then I'll override them using request-specific data if I need to. Eg:

```go
package html

type Template struct {
  template *template.Template
}

func ParseFiles(files ...string) (*Template, error) {
  tpl, err := template.New("").Funcs(template.FuncMap{
    "flash": func() string { return "" },
  }).ParseFiles(files...)
  if err != nil {
    return nil, fmt.Errorf("parsing view files: %w", err)
  }
  return &Template{
    template: tpl,
  }, nil
}

func (t *Template) Execute(w http.ResponseWriter, r *http.Request, data interface{}) {
  // clone the template BEFORE adding user-specifics!
  clone := t.clone()

  // Get the flash cookie
	cookie, err := r.Cookie("flash")
	switch err {
  case nil:
    // override the flash msg
    clone.template = clone.template.Funcs(template.FuncMap{
      "flash": func() string { return cookie.Value },
    })
		// Delete the flash cookie so we don't repeat it.
		expired := http.Cookie{ ... }
		http.SetCookie(w, &expired)
	default:
		// noop
	}

  err = clone.template.Execute(w, data)
	if err != nil { ... }
}
```


*Sidenote: I talk about some additional ideas to try with the view package in an older article [Creating the V in MVC](https://www.calhoun.io/intro-to-templates-p4-v-in-mvc/). I'm not saying I'd recommend them all at this point, but they are worth looking over as a mental exercise.*



### What goes in the `controllers` package?

If you get the other two right, this package ends up being pretty boring. You basically just create `http.Handler`s that parse incoming data, call methods on something like a `UserStore` or `CourseStore` provided by your `models` package, then finally render the results via a view (or redirect the user to an appropriate page in some cases).

```go
// Take note: our UserHandler has a UserStore injected in!
// Global data stores can be problematic long term.
type UserHandler struct {
  Users    models.UserStore
  Sessions models.SessionStore
}

func (uh *UserHandler) Create(w http.ResponseWriter, r *http.Request) {
  err := r.ParseForm()
  if err != nil { ... }

  var form struct {
    Email    string `schema:"email"`
    Password string `schema:"password"`
  }
  schema.NewDecoder().Decode(&form, r.PostForm)
  user := sql.User{
    Email: form.Email,
    Password: form.Password,
  }
  err = uh.Users.Create(&user)
  if err != nil { ... }

  token, err := uh.Session.Create(&user)
  if err != nil { ... }
  // create session cookie using token

  http.Redirect(w, r, "/dashboard", http.StatusFound)
}
```

You might occasionally find yourself defining custom types to help render views, and to this day I'm still unsure of where the best place is for them. In one sense they are view specific, since your view will rely on a very specific set of data being passed in to render correctly. In that case they should probably be defined inside the `views` package (or a nested package). On the other hand, your controller *could* conceivably render data in various formats - HTML, JSON, or XML - so I could also see an argument for placing a creating a custom type that is "returned" from each handler inside the controllers package.

I think both can work, so if you do need custom types pick the one that works for you and roll with it. Even if you end up needing to change this decision, it shouldn't be too hard to refactor.


## Don't blindly copy other languages

At this point I hope you are starting to see how MVC can be successfully implemented in Go, but I can't end this article without also discussing some of mistakes you might try to copy from other languages that utilized MVC.

Let's take a second to look at what a model might do in an MVC framework like Ruby on Rails:

1. While the model usually maps to the DB, it is also expected to serve the entire application's needs (eg UI rendering)
2. Your application has global access to models and other entities like `current_user`
3. Models have methods that trigger additional SQL queries based on relational data

While it is possible to implement many of these "features" in Go, I would never recommend it. So let's look at alternatives.

### You will need to define resources more than once

In Rails we might define a model once and then expect it to work across our entire application. There are several ways we do this, but it mostly revolves around:

1. Creating methods that translate data
2. Creating wrapper types, like a decorator

While it is possible to create a Go web application where the only time you define your resources is in the `models` package, it is more likely that you will eventually need to define a second version of each resource. For instance, imagine we were rendering a `User` for a JSON response - if we were to use the `models` definition of a user we would need to add all of those json struct tags to the models package even though it has nothing to do with the code there. We would also potentially need to write custom marshalling code there to handle the fact that what we store in the database isn't exactly what we want to render to the user.

You are almost always better off just creating a new type and writing code to translate between the two:

```go
package json // view

type User struct { ... }
```

```go
package sql // model

type User struct { ... }
```

```go
package http // controller

func sqlUserToJson(user *sql.User) json.User { ... }
```

Yes, it is more code, but you (hopefully) didn't pick Go because it was the least verbose language available to you.


### Globals are a bad idea

In languages like Ruby or Python your server is most likely handling a single web request at a time. This isn't the fastest way to do things, but it does make development significantly easier because you can create global functions like `current_user` and know that they only pertain to the current request.

Go is nothing like Ruby or Python in this sense. When a web request comes into your Go server the standard library will spin up a new goroutine to handle it and then start to pass the request along to your handlers. This is incredibly handy from a developers perspective because we don't have to do anything to make our web server work concurrently, but it also means that adding a global function like `current_user` would lead to all sorts of race conditions.

Even a global database connection, which isn't as error prone, is ill-advised. While you might not have race conditions, a global database will allow SQL queries to be executed from anywhere in your application. If you were to instead just inject your data stores into the rest of your code it is much easier to track where queries are being made from, it is easier to test, and your life will generally just be much better.

```go
func main() {
  userStore := sql.NewUserStore(...)
  // Inject the userStore where it is needed!
  userController := http.NewUserHandler(userStore)

  // ... setup the rest of your app
}
```

### Don't embed DB connections to make relational queries possible

While it is possible to make relational queries work in Go much like they do in dynamic languages, I wouldn't recommend it.

```go
package sql

type OrderStore struct {
  db *sql.DB
}

func (os *OrderStore) ByUserID(id int) ([]Order, error) {
  // ...
}

type User struct {
  ID int
  // ...

  // Don't do this
  db *sql.DB
}

func (u *User) Orders() ([]Order, error) {
  os := OrderStore{u.db}
  return os.ByUserID(u.ID)
}
```

The reasons are basically the same why we avoid a global database connection; it can lead to all sorts of hidden complexity. I write a bit more about this in my article [Subtle issues with ORMs and how to avoid them](https://www.calhoun.io/subtle-issues-with-orms-and-how-to-avoid-them/), but the main takeaway is that when this is possible, a SQL query can literally be triggered from anywhere in your application, not just where you inject the `OrderStore`, and as a result it can make it very hard to manage your application.


## In summary...

We spent the last bit of this article talking about things not to do, but really what I want you to take away from this article are all the things before that. I want you to understand that MVC can, and does, work in Go. That MVC is less about what you name your packages, and more about how you organize your code. If you keep that in mind I suspect you will have no problems using MVC in your next web application.


## Want to learn Go?

Interested in learning or practicing Go? Check out my FREE course - [Gophercises - Programming Exercises for Budding Gophers](https://gophercises.com).

I also have some premium courses that cover [Web Dev with Go](https://www.usegolang.com/) and [Testing with Go](https://testwithgo.com/) that you can check out as well.