Skip to main content

Black Friday 2025! Only until December 1st: coupon FRIDAY25 for 40% off Yearly/Lifetime membership!

Read more here
Premium Members Only
Join to unlock this tutorial and all of our courses.
Tutorial Premium Tutorial

Laravel API Versioning: All You Need To Know About V1/V2

July 03, 2023
18 min read

Tutorial last revisioned on June 12, 2025 with Laravel 12

Have you ever used an external API and specified its version? For example, have you noticed the /v1/ in the URL of https://api.openai.com/v1/models? In this tutorial, I will explain how to use similar versioning for our own APIs we create with Laravel.

In this long tutorial, we will discuss these topics:

  • WHY we need versioning?
  • How to enable V1 from the beginning
  • WHEN to implement V2?
  • HOW to implement V2?
  • Minor versions like v1.1
  • Date-based version numbers
  • Versioning with headers

A lot to cover. Let's go!


WHY We Need Versioning? What Problem Does It Solve?

If we take OpenAI, for example, here's the screenshot from their API documentation:

Have you noticed the /v1/ as a part of the URL? That's the version.

That "version 1" means stable methods/parameters/results for everyone who would consume that API version. If they introduce breaking changes for some methods, like renaming parameters or returned result structure, that may be a candidate for a future /v2/.

The same logic applies not only to external APIs. What about Laravel packages? If you use, for example, spatie/laravel-permission version 5, you expect it to work stable, but what if they decide to change some methods? They would likely do that in version 6, right?

Even Laravel itself is a package called laravel/framework. And with each new version, there's an upgrade guide with potential breaking changes, small or big. If any of those changes are introduced in a "minor" 10.x version like 10.x and not 11.0, developers may be unhappy because their code would break.

So, in a broader sense, the word API means the interface, the set of strict rules for the available methods, which would be consumed by API client(s). Without the versioning, it would all be unstable, and the projects on the consumer's side would break with any change in the API.

That's why we need v1, v2, etc. Especially if you don't have any control of the consumers of the API, the most significant example is mobile applications: you can't force everyone always to upgrade apps on their phones, right?

Of course, version numbers could have a different logic, like v1.2.4, or even numbered by the release date, like 2023-04-28.

We will talk about all of that in detail below.

Generally speaking, you may not need API versioning if the only consumer of that API is yourself in your front-end code. Then you can make changes on both the front and back end and make it work. But even then, you never know when the project will expand and needs Android/iOS applications and a bigger team of developers. So the earlier you introduce versioning, the better.


Enable V1 From The Beginning

I recently tweeted this:

The tweet became pretty popular, and I will explain it similarly to you here.

Introducing /v1/ as a part of Laravel API endpoints is pretty straightforward:

Step 1. Prefix all the default...

Premium Members Only

This advanced tutorial is available exclusively to Laravel Daily Premium members.

Premium membership includes:

Access to all premium tutorials
Video and Text Courses
Private Discord Channel

Comments & Discussion

J
jakub ✓ Link copied!

Another way to achieve versioning is to use content negotiation header:

Accept: application/json+v1

If versioned API is stored in directory structure like:

App/Api/V1/Authors/AuthorsController.php

Then header can be used in such way:

$version = strtoupper(explode('+', RequestFacade::header('Accept', '+v1'))[1]);

Route::prefix('/')->namespace('App\Api\' . $version)->group(function () { Route::apiResource('authors', Authors\AuthorsController::class); });

And endpoint can be accesed via such uri:

/api/authors

Above does not verify if cotroller physicaly exists.

VR
Viktor Riedel ✓ Link copied!

would be good to add something like Route::namespace('v1')->group...and Route::namespace('v2')->group to separate functionality inside your app

KA
Kashif Amin ✓ Link copied!

How to configure RouteServiceProvider if we want to keep both versions available for the clients?

PK
Povilas Korop ✓ Link copied!

Then you leave both versions in the RouteServiceProvider. Or maybe I misunderstood the question.

KA
Kashif Amin ✓ Link copied!

If in an Application, some users fetch data from v1 and some from v2. How to impliment this scenerio. Forexample, i have an experience of integrating my client's Web Application to a third party Retail System. The Retails System company provided the api with prefix /V1. I have integrated it successfully. After some months, the Reail System company ask all its customer to update the prefix to /V2 in their Applications. At that time, i noticed that their both versions was working. How would they made this happened. (Appologies for bad English)

M
Modestas ✓ Link copied!

In that case, you need to have a complete set of controllers and routes for the V1 still available, while also having the V2 up.

This does usually mean separate controllers, API resources, services and everything else per version.

MS
Mike Scott ✓ Link copied!

Note that using an "X-" prefix in your headers has been deprecated since 2012. See the top answer in this StackOverflow question and the official RFC 6648.

M
Modestas ✓ Link copied!

Hi, thanks for letting us know!

I think this was more of a habbit to add it, than a requirement :) Updated the post!

SB
Shadyar Bzhar Othman ✓ Link copied!

Thanks for this tutorial, I have two questions:

  • Do I need to version [Migration, Model]?
  • If my migration can be change so the database design will change and as I understand if you introduce you can have required field which is not in the old version, so my question is the database that store all data for all version will not work for older version unless we have a new database?

I don't know if I'm wrong!

M
Modestas ✓ Link copied!

It really depends on how the API is used. But in general:

All future additions to database, models should be backwards compatible. So if you add a required field - you need to have it nullable in the database. That way nothing breaks!

In any case, this really depends on the use-case :)

SB
Shadyar Bzhar Othman ✓ Link copied!

Thanks!

A
angel ✓ Link copied!

Thanks for the tutorial. What are the files that need versionning ? Should i version the model/migrations for example ?

N
Nerijus ✓ Link copied!

Your question is answered above. Quote:

It really depends on how the API is used. But in general:

All future additions to database, models should be backwards compatible. So if you add a required field - you need to have it nullable in the database. That way nothing breaks!

In any case, this really depends on the use-case :)