{"id":2989,"date":"2024-11-27T02:27:05","date_gmt":"2024-11-27T02:27:05","guid":{"rendered":"https:\/\/www.aviator.co\/blog\/?p=2989"},"modified":"2025-09-23T12:42:48","modified_gmt":"2025-09-23T12:42:48","slug":"trunk-based-development-in-microservices","status":"publish","type":"post","link":"https:\/\/www.aviator.co\/blog\/trunk-based-development-in-microservices\/","title":{"rendered":"Trunk-Based Development for Microservices: What You Need to Know"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img fetchpriority=\"high\" decoding=\"async\" width=\"1024\" height=\"576\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/11\/Copy-of-3-Factors-that-Comparison-of-Tools1-1024x576.png\" alt=\"\" class=\"wp-image-3020\" srcset=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/11\/Copy-of-3-Factors-that-Comparison-of-Tools1-1024x576.png 1024w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/11\/Copy-of-3-Factors-that-Comparison-of-Tools1-300x169.png 300w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/11\/Copy-of-3-Factors-that-Comparison-of-Tools1-768x432.png 768w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/11\/Copy-of-3-Factors-that-Comparison-of-Tools1-1536x864.png 1536w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/11\/Copy-of-3-Factors-that-Comparison-of-Tools1.png 1920w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><a href=\"https:\/\/www.aviator.co\/blog\/trunk-based-development\/\" target=\"_blank\" rel=\"noopener\" title=\"Trunk-based development (TBD)\">Trunk-based development (TBD)<\/a> is an effective approach for version control, known for reliable, quick deployments with short lived branching. This approach encourages continuous integration and reduces merge conflicts by focusing on a single primary branch where developers commit frequently.<\/p>\n\n\n\n<p>TBD is especially beneficial for microservices, as teams manage multiple services that must collaborate and be updated independently. The continuous integration of changes makes trunk-based development multiple environments ideal for swift updates while maintaining stability.<\/p>\n\n\n\n<p>In contrast to Trunk-based development, architectures like feature branching and Gitflow are more complex to set up and work with.&nbsp;<\/p>\n\n\n\n<p>This blog will explore:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>How trunk-based development compares to feature branching and Gitflow, and how it addresses their limitations<\/li>\n\n\n\n<li>Core principles of TBD, and its benefits over other approaches.&nbsp;<\/li>\n\n\n\n<li>A hands-on trunk-based development example which will include setting up a repository, committing to the main branch, building a simple microservice, writing unit tests, and integrating CI\/CD pipelines.<\/li>\n\n\n\n<li>Additionally, we\u2019ll also look at using\n<ul class=\"wp-block-list\">\n<li>Short-lived feature branches<\/li>\n\n\n\n<li>Conflict resolution<\/li>\n\n\n\n<li>Rollback techniques&nbsp;<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img decoding=\"async\" width=\"724\" height=\"461\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/11\/tbd.png\" alt=\"\" class=\"wp-image-3167\" style=\"width:750px;height:auto\" srcset=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/11\/tbd.png 724w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/11\/tbd-300x191.png 300w\" sizes=\"(max-width: 724px) 100vw, 724px\" \/><figcaption class=\"wp-element-caption\">Trunk-Based Development<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Understanding Trunk-Based Development<\/strong><\/h2>\n\n\n\n<p><a href=\"https:\/\/www.aviator.co\/blog\/trunk-based-development\/\" title=\"\">Trunk-based development<\/a> centers around making frequent, modest commits to the main branch. Developers work directly on the main branch instead of creating separate feature branches, enabling continuous integration. This approach maintains project stability and allows early problem detection.<\/p>\n\n\n\n<p>In comparison,<strong> Feature branching <\/strong>makes distinct branches for every feature, which can remain isolated for weeks. Although this keeps things structured, it frequently results in bigger, more complex mergers and increases conflicts. Additionally, insufficient testing on isolated branches may delay bug detection.<\/p>\n\n\n\n<p>Similarly,<strong> Gitflow<\/strong> uses multiple branches for development, features, and releases. Although it offers organizational structure, it can slow development with strict branch rules, creating bottlenecks and delays. This can be challenging in fast-paced environments where quick updates are needed.<\/p>\n\n\n\n<p>With TBD, developers integrate changes into the main branch as soon as they\u2019re ready, keeping changes small and testing them continuously. This reduces merge conflicts and maintains stability, enabling faster releases. TBD particularly suits fast-paced environments where quick, regular updates across multiple services are essential. By avoiding long-lived branches, TBD allows for smoother integration and quicker deployments.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Trunk-Based Development for Microservices<\/strong><\/h2>\n\n\n\n<p>Trunk-based development focuses on small, short-lived branches that merge into a single main branch. Integrating incremental changes reduces conflict by catching issues early, leading to less rework. This approach excels in microservices environments where frequent service interactions make updates potentially disruptive.<\/p>\n\n\n\n<p>TBD streamlines update coordination across services as all teams work against a single branch. Teams discover incompatibilities immediately when changes occur, rather than during the end of a sprint or branch merges. Continuous integration ensures every commit is tested, enabling early bug detection.<\/p>\n\n\n\n<p>For example, a retail company uses microservices for inventory, payments, and customer accounts. A payments team implementing a new payment method can integrate changes progressively. Every change is tested automatically against dependent services like inventory updates and customer purchase history. Through small, continuous updates, TBD enables smooth feature deployment while maintaining service synchronization.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Using Trunk-Based Development<\/strong> for Microservices<\/h2>\n\n\n\n<p>Let\u2019s walk through the process of setting up a simple &#8220;<em>Hello World<\/em>&#8221; microservice while following the principles of Trunk-Based Development. This hands-on trunk-based development example will demonstrate how to commit changes frequently, integrate continuously, and use automated testing, all while maintaining a stable and efficient codebase.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Creating the Repository<\/strong><\/h3>\n\n\n\n<p>The first step is to create a new Git repository with a single main branch. Let\u2019s say that our project directory is called TBD-Test, use the following command to create a folder and initialize Git in the repository:&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mkdir TBD-Test\ngit init<\/code><\/pre>\n\n\n\n<p>Add a remote link to the upstream repository, which is housed on GitHub.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>git remote add &lt;link-to-upstream-repository&gt;<\/code><\/pre>\n\n\n\n<p>In TBD, developers work in short-lived feature branches that are quickly reviewed and merged into the main branch. Development prioritizes maintaining a stable, current main branch. Limiting branch lifetimes simplifies codebase stability and accelerates change integration.<\/p>\n\n\n\n<p>Instead of direct commits to the main branch, branch protections and restrictions ensure changes undergo necessary reviews. Pull requests serve as the standard method for merging changes, enabling thorough review, automated checks, and maintaining codebase stability before merging.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Project Structure<\/h3>\n\n\n\n<p>Once the repository is set up, define a simple project structure to ensure organized building, testing, and deployment. Let&#8217;s take two microservices: a &#8220;Hello World&#8221; API and a &#8220;Bye World&#8221; API.<\/p>\n\n\n\n<p>Once the repository is set up, it\u2019s time to define a simple structure for your project. This keeps everything organized and ensures that the application can be easily built, tested, and deployed.<\/p>\n\n\n\n<p>The Project structure consists of:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>hello-api\/app\/ folder<\/strong> \u2013 Contains the core application code which is a simple flask program which will respond with \u201cHello World\u201d upon request.<\/li>\n\n\n\n<li><strong>bye-api\/app\/ folder<\/strong> \u2013 Contains the core application code which is a simple flask program which will respond with \u201cBye\u201d upon request.<\/li>\n\n\n\n<li><strong>hello-api\/test\/ folder<\/strong> \u2013 Responsible for unit and integration tests for your hello-api service.<\/li>\n\n\n\n<li><strong>bye-api\/test\/ folder<\/strong> \u2013 Responsible for unit and integration tests for your bye-api service.<\/li>\n\n\n\n<li><strong>README.md<\/strong> \u2013 Basic documentation for setting up and running the service.<\/li>\n<\/ul>\n\n\n\n<p>So the project contents look like this:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">.<br>\u251c\u2500\u2500 bye-api<br>\u251c\u2500\u2500 hello-api<br>\u2514\u2500\u2500 README.md<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Frequent Commits<\/h3>\n\n\n\n<p>When using TBD, each commit should be small, isolated task for smooth integration and to catch issues early. So these changes would be committed via a short-lived feature branch called <code>file-structure<\/code>, and create a pull request using <a href=\"https:\/\/cli.github.com\/\" title=\"\">GitHub CLI<\/a>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>gh pr create --title \"Basic file structure\" --body \"\"<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Developing the &#8220;Hello World&#8221; Microservice<\/strong><\/h3>\n\n\n\n<p>We\u2019ll use Flask to build the &#8220;<em>Hello World<\/em>&#8221; microservice, but the same principles can also be applied to other frameworks and programming languages. The service will have a simple <code>\/hello<\/code> endpoint that responds with the message &#8220;Hello, World!&#8221;.<\/p>\n\n\n\n<p>Go to the app folder and create two files named __init__.py and routes.py.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cd hello-api\nmkdir app\ntouch __init__.py\ntouch routes.py<\/code><\/pre>\n\n\n\n<p>The <code>__init__.py<\/code> file is typically used for initializing your Flask app and any configurations, while the logic for specific routes and functionality can go in separate modules. <\/p>\n\n\n\n<p>Contents of  <code>__init__.py<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>from flask import Flask\n\napp = Flask(__name__)\n\nfrom app import routes<\/code><\/pre>\n\n\n\n<p>The <code>routes.py<\/code> contains the logic for all the routes:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>from app import app\n\n@app.route('\/hello')\ndef hello_world():\n&nbsp; &nbsp; return \"Hello, World!\"<\/code><\/pre>\n\n\n\n<p>This is the simplest version of the service and is ready to be tested. Now, commit this change to a new branch <code>hello-feature<\/code> and raise a PR:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>git checkout -b hello-feature\ngit add .\ngit commit -m \"Add the \/hello endpoint to return Hello World message\"\ngit push origin hello-feature\ngh pr create --title \"Add \/hello endpoint\" --body \"\"<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Automated Testing<\/strong><\/h3>\n\n\n\n<p>Testing is a key part of trunk-based development. To maintain stability, ensure that every change is automatically tested before merging into the main branch. Let\u2019s add a simple unit test to verify that the <strong>\/hello<\/strong> endpoint works as expected.<\/p>\n\n\n\n<p>First, navigate to the Root directory of the Hello World microservice and create a test file <code>app-test.py<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import unittest\nfrom app import app\n\nclass TestHelloWorld(unittest.TestCase):\n&nbsp; &nbsp; def setUp(self):\n&nbsp; &nbsp; &nbsp; &nbsp; self.app = app.test_client()\n\n&nbsp; &nbsp; def test_hello(self):\n&nbsp; &nbsp; &nbsp; &nbsp; response = self.app.get('\/hello')\n&nbsp; &nbsp; &nbsp; &nbsp; self.assertEqual(response.data.decode(), \"Hello, World!\")\n\nif __name__ == '__main__':\n&nbsp; &nbsp; unittest.main()<\/code><\/pre>\n\n\n\n<p>Add it to the already stacked list of commits:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>git checkout -b hello-test\ngit add .\ngit commit -m \"Add the test for \/hello endpoint\"\ngit push origin hello-test<\/code><\/pre>\n\n\n\n<p>Create a new pull request:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>gh pr create --title \"Add a test for \/hello endpoint\" --body \"\"<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Continuous Integration Pipeline<\/strong><\/h3>\n\n\n\n<p>Set up a CI pipeline using GitHub Actions that runs these tests automatically every time a commit is made to the main branch. This ensures that the code remains stable, and that any issues are caught early.<\/p>\n\n\n\n<p>Create a workflow file <code>hello-ci.yaml<\/code> file in <code>.github\/workflows<\/code> directory. This file will specify how the tests should run on each commit to the main branch.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>name: Hello CI Pipeline\n\non:\n&nbsp; push:\n&nbsp; &nbsp; branches:\n&nbsp; &nbsp; &nbsp; - main\n&nbsp; pull_request:\n&nbsp; &nbsp; branches:\n&nbsp; &nbsp; &nbsp; - main\n\njobs:\n&nbsp; test:\n&nbsp; &nbsp; runs-on: ubuntu-latest\n\n&nbsp; &nbsp; services:\n&nbsp; &nbsp; &nbsp; docker:\n&nbsp; &nbsp; &nbsp; &nbsp; image: python:3.9\n&nbsp; &nbsp; &nbsp; &nbsp; options: --network host\n\n&nbsp; &nbsp; steps:\n&nbsp; &nbsp; &nbsp; - name: Checkout code\n&nbsp; &nbsp; &nbsp; &nbsp; uses: actions\/checkout@v2\n\n&nbsp; &nbsp; &nbsp; - name: Set up Python\n&nbsp; &nbsp; &nbsp; &nbsp; uses: actions\/setup-python@v2\n&nbsp; &nbsp; &nbsp; &nbsp; with:\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; python-version: '3.9'\n\n&nbsp; &nbsp; &nbsp; - name: Install dependencies\n&nbsp; &nbsp; &nbsp; &nbsp; run: |\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; python -m pip install --upgrade pip\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pip install flask\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pip install -r requirements.txt || true\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\n&nbsp; &nbsp; &nbsp; - name: Run tests\n&nbsp; &nbsp; &nbsp; &nbsp; run: |\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; python -m unittest discover -s hello-api\/test<\/code><\/pre>\n\n\n\n<p>This CI pipeline is triggered on every pull requests targeting the main branch. To maintain code quality and stability, branch protection rules can be configured to ensure that these pull requests cannot be merged until the CI pipeline completes successfully. This guarantees that all automated tests and checks pass before any changes are integrated into the main branch.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Short-Lived Feature Branches<\/strong><\/h2>\n\n\n\n<p>In trunk-based development, frequent merges to the main branch help spot and fix conflicts early, keeping the codebase stable. <a href=\"https:\/\/github.com\/aviator-co\/av\">Aviator\u2019s av CLI<\/a> manages conflicts effectively with stacked PRs by creating and managing Short-Lived Feature Branches. To setup CLI, read the <a href=\"https:\/\/docs.aviator.co\/aviator-cli\/quickstart\" title=\"quick start guide\">quick start guide<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>What Are Stacked PRs<\/strong><\/h3>\n\n\n\n<p><a href=\"https:\/\/www.aviator.co\/blog\/stacked-prs-code-changes-as-narrative\/\" title=\"Stacked PRs\">Stacked PRs<\/a> involve creating multiple small, focused pull requests that build on top of each other. Each PR includes a specific change, making it easier to review and test. Instead of working on a large, complex PR, developers can submit manageable updates one at a time, which reduces integration problems. Stacked PRs help keep the main branch stable while allowing incremental changes to be added without causing delays or conflicts.<\/p>\n\n\n\n<p>For each small change, create a new short-lived branch:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>av stack branch &lt;branch_name&gt;<\/code><\/pre>\n\n\n\n<p>And then synchronize changes across the entire stack:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>av stack sync<\/code><\/pre>\n\n\n\n<p>This lets you work on each change separately and synchronize changes as you made improvements anywhere in the stack, keeping things simple and reducing the risk of conflicts.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Using Stacked PRs for Trunk-Based Development<\/h3>\n\n\n\n<p>Let&#8217;s create a temporary branch, add specific changes, test them, and then merge the branch back into the main branch once all checks pass.<\/p>\n\n\n\n<p>You can check out the official <a href=\"https:\/\/github.com\/aviator-co\/av\/\">GitHub<\/a> page for installation instructions for your specific operating system. After you are done installing the CLI tool, link it to GitHub. In order to interact with GitHub, av uses the GitHub API token. If you have a GitHub CLI installed, av will automatically use the token from the GitHub CLI. It is recommended to install both.<\/p>\n\n\n\n<p>Use av CLI to create a new branch:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>av stack branch bye-endpoint<\/code><\/pre>\n\n\n\n<p>Go to the app folder and create a two files&nbsp; named <code>__init__.py<\/code> and <code>routes.py<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">__init__.py<\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>from flask import Flask\n\napp = Flask(__name__)\n\nfrom app import routes<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\">routes.py<\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>from app import app\n\n@app.route('\/bye')\ndef bye_world():\n&nbsp; &nbsp; return \"Bye, World!\"<\/code><\/pre>\n\n\n\n<p>Commit the change to the local repository and raise a PR with av CLI.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>git add .\ngit commit -m \"Add \/bye endpoint to the microservice\"\nav pr create<\/code><\/pre>\n\n\n\n<p>This command creates or updates a PR in the stacked branch you created. Next, add a unit test to ensure the new functionality works as expected. Create another stacked branch from the current bye-endpoint branch:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>av stack branch test-bye-endpoint<\/code><\/pre>\n\n\n\n<p>Navigate to the Root directory of the Hello World microservice and create a test directory with <code>app-test.py<\/code> file.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import unittest\nfrom app import app\n\nclass TestByeWorld(unittest.TestCase):\n&nbsp; &nbsp; def setUp(self):\n&nbsp; &nbsp; &nbsp; &nbsp; self.app = app.test_client()\n\n&nbsp; &nbsp; def test_bye(self):\n&nbsp; &nbsp; &nbsp; &nbsp; response = self.app.get('\/bye')\n&nbsp; &nbsp; &nbsp; &nbsp; self.assertEqual(response.data.decode(), \"Bye, World!\")\n\nif __name__ == '__main__':\n&nbsp; &nbsp; unittest.main()<\/code><\/pre>\n\n\n\n<p>Commit the change to the local repository and raise a PR with av CLI.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>git add .\ngit commit -m \"Add test for \/bye endpoint\"\nav pr create<\/code><\/pre>\n\n\n\n<p>This will create an additional PR that is stacked on top of the PR created in the previous step. This ensures that each change can be independently reviewed and revised while keeping the entire stack in sync.<\/p>\n\n\n\n<p>Now, create a GitHub Action CI for the Bye World microservice as well. Create another stacked branch from the current test-bye-endpoint branch using <code>av stack branch<\/code> command:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>av stack branch bye-ci<\/code><\/pre>\n\n\n\n<p>Navigate to the .github\/workflow folder and create a <code>bye-ci.yaml<\/code> file for the Bye World Microservice as well.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>name: Bye CI Pipeline\n\non:\n&nbsp; push:\n&nbsp; &nbsp; branches:\n&nbsp; &nbsp; &nbsp; - main\n&nbsp; pull_request:\n&nbsp; &nbsp; branches:\n&nbsp; &nbsp; &nbsp; - main\n\njobs:\n&nbsp; test:\n&nbsp; &nbsp; runs-on: ubuntu-latest\n\n&nbsp; &nbsp; services:\n&nbsp; &nbsp; &nbsp; docker:\n&nbsp; &nbsp; &nbsp; &nbsp; image: python:3.9\n&nbsp; &nbsp; &nbsp; &nbsp; options: --network host\n\n&nbsp; &nbsp; steps:\n&nbsp; &nbsp; &nbsp; - name: Checkout code\n&nbsp; &nbsp; &nbsp; &nbsp; uses: actions\/checkout@v2\n\n&nbsp; &nbsp; &nbsp; - name: Set up Python\n&nbsp; &nbsp; &nbsp; &nbsp; uses: actions\/setup-python@v2\n&nbsp; &nbsp; &nbsp; &nbsp; with:\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; python-version: '3.9'\n\n&nbsp; &nbsp; &nbsp; - name: Install dependencies\n&nbsp; &nbsp; &nbsp; &nbsp; run: |\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; python -m pip install --upgrade pip\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pip install flask\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pip install -r requirements.txt || true\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\n&nbsp; &nbsp; &nbsp; - name: Run tests\n&nbsp; &nbsp; &nbsp; &nbsp; run: |\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; python -m unittest discover -s bye-api\/test<\/code><\/pre>\n\n\n\n<p>Commit the change to the local repository, and open a PR:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>git add .\ngit commit -m \"Add CI Pipeline\"\nav pr create<\/code><\/pre>\n\n\n\n<p>Now, Open the pull request from the feature branch to the main. This is where the CI pipeline will automatically run tests to verify the new feature\u2019s stability. Once all tests pass in the CI pipeline, you can review the code and <a href=\"https:\/\/docs.aviator.co\/mergequeue\/how-to-guides\/merging-stacked-prs\" title=\"\">merge the entire stack together<\/a> or separately into the main branch.<\/p>\n\n\n\n<p>Once these PRs are merged, you can easily delete the temporary branch locally and remotely using the sync command:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>av stack sync --rebase-to-trunk<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Syncing and Keeping Branches Up-to-Date<\/strong><\/h3>\n\n\n\n<p>As you work on multiple stacks, you can use:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>av stack sync --all&nbsp;<\/code><\/pre>\n\n\n\n<p>This will update and rebase all the branches across all your stacks regularly. This command ensures that the commits in any part of the stack are propagated across the entire stack, ensuring that each branch is up to date with the latest code and avoiding surprises later on.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Visualizing and Organizing Stacked PRs:<\/strong><\/h3>\n\n\n\n<p>To see an overview of all your branches and their order, use:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>av stack tree<\/code><\/pre>\n\n\n\n<p>This gives you a clear view of how branches relate to each other, helping you manage and merge them in the right order. If you need to adjust the order of branches or commits, you can use:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>av stack reorder<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Branch Protection<\/h3>\n\n\n\n<p><a href=\"https:\/\/docs.github.com\/en\/repositories\/configuring-branches-and-merges-in-your-repository\/managing-protected-branches\/managing-a-branch-protection-rule\" title=\"\">GitHub Branch protection best practices<\/a> ensure that only validated changes are merged into the protected branches. With conditional CI pipelines, you should focus on requiring specific checks to pass before allowing merges.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Running Separate CIs for Different Microservices<\/strong><\/h4>\n\n\n\n<p>To run separate CI workflows for different microservices within the same monorepo, you can modify the GitHub Actions workflow files to use path filters. This ensures that CI runs only when relevant files are changed.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">.github\/workflows\/hello-ci.yaml<\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>name: Hello CI Pipeline\n\non:\n&nbsp; push:\n&nbsp; &nbsp; branches:\n&nbsp; &nbsp; &nbsp; - main\n&nbsp; &nbsp; paths:\n&nbsp; &nbsp; &nbsp; - 'hello-api\/**'\n&nbsp; pull_request:\n&nbsp; &nbsp; branches:\n&nbsp; &nbsp; &nbsp; - main\n&nbsp; &nbsp; paths:\n&nbsp; &nbsp; &nbsp; - 'hello-api\/**'\n\njobs:\n&nbsp; test:\n&nbsp; &nbsp; runs-on: ubuntu-latest\n&nbsp; &nbsp;\n&nbsp; &nbsp; <em># Add status check name for branch protection<\/em>\n&nbsp; &nbsp; name: Hello API Tests\n\n&nbsp; &nbsp; steps:\n&nbsp; &nbsp; &nbsp; <em># Previous steps remain the same<\/em>\n&nbsp; &nbsp; &nbsp;\n&nbsp; &nbsp;   <em># Add explicit status check<\/em>\n&nbsp; &nbsp;   - name: Report status\n&nbsp; &nbsp; &nbsp;   if: always()\n&nbsp; &nbsp; &nbsp;   run: |\n&nbsp; &nbsp; &nbsp; &nbsp;   if &#91; ${{ job.status }} == 'success' ]; then\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;   exit 0\n&nbsp; &nbsp; &nbsp; &nbsp;   else\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;   exit 1\n&nbsp; &nbsp; &nbsp; &nbsp;   fi<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\">.github\/workflows\/bye-ci.yaml<\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>name: Bye CI Pipeline\n\non:\n&nbsp; push:\n&nbsp; &nbsp; branches:\n&nbsp; &nbsp; &nbsp; - main\n&nbsp; &nbsp; paths:\n&nbsp; &nbsp; &nbsp; - 'bye-api\/**'\n&nbsp; pull_request:\n&nbsp; &nbsp; branches:\n&nbsp; &nbsp; &nbsp; - main\n&nbsp; &nbsp; paths:\n&nbsp; &nbsp; &nbsp; - 'bye-api\/**'\n\njobs:\n&nbsp; test:\n&nbsp; &nbsp; runs-on: ubuntu-latest\n&nbsp; &nbsp;\n&nbsp; &nbsp; <em># Add status check name for branch protection<\/em>\n&nbsp; &nbsp; name: Bye API Tests\n\n&nbsp; &nbsp; steps:\n&nbsp; &nbsp; &nbsp; <em># Previous steps remain the same<\/em>\n&nbsp; &nbsp; &nbsp;\n&nbsp; &nbsp;   <em># Add explicit status check<\/em>\n&nbsp; &nbsp;   - name: Report status\n&nbsp; &nbsp; &nbsp;   if: always()\n&nbsp; &nbsp; &nbsp;   run: |\n&nbsp; &nbsp; &nbsp; &nbsp;   if &#91; ${{ job.status }} == 'success' ]; then\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;   exit 0\n&nbsp; &nbsp; &nbsp; &nbsp;   else\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;   exit 1\n&nbsp; &nbsp; &nbsp; &nbsp;   fi<\/code><\/pre>\n\n\n\n<p>This ensures that a status check is reported as success when the file is not modified for the related service. This status check can then be used in the branch protection rules.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Branch Protection Rules with Conditional CIs<\/strong><\/h4>\n\n\n\n<p>Now, let&#8217;s set up branch protection rules that work with our conditional CI setup:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Go to your repository settings.<\/li>\n\n\n\n<li>Navigate to &#8220;Branches&#8221; under &#8220;Code and automation&#8221;.<\/li>\n\n\n\n<li>Click &#8220;Add classic branch protection rules&#8221; under &#8220;Branch protection rules&#8221;.<\/li>\n\n\n\n<li>For &#8220;Branch name pattern,&#8221; enter main. Then click on the checkboxes with these rules:\n<ul class=\"wp-block-list\">\n<li>Require a pull request before merging<\/li>\n\n\n\n<li>Require status checks to pass before merging.<\/li>\n\n\n\n<li>Select both the status checks &#8220;Bye API Tests&#8221; and &#8220;Hello API Tests&#8221; as required checks<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p>With this, your branch protection will be applied.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Integrating Aviator MergeQueue<\/h3>\n\n\n\n<p>By integrating the Aviator\u2019s MergeQueue, there will be an additional layer of safety, making it easy to incorporate new features into the system, which has an orderly way of merging. MergeQueue ensures that any changes that are merged in mainline are validated with the latest code changes.<\/p>\n\n\n\n<p>It <a href=\"https:\/\/www.aviator.co\/blog\/what-is-a-merge-queue\/\" title=\"\">combines all queued changes sequentially<\/a>, executing CI tests over the resultant code base, and later merging such changes to avoid the problems of broken builds associated with conflicting modifications. It enhances the integration of these changes while preserving the state of branches and offers further assurance that only carefully tested modifications are integrated.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">.github\/workflows\/aviator.yaml<\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>version: 1.0.0\nmerge_rules:\n  labels:\n    trigger: mergequeue\n    skip_line: skip-line\n  require_all_checks_pass: true\n  publish_status_check: true\n  ci_timeout_mins: 20\n  preconditions:\n    use_github_mergeability: false\n\n  merge_mode:\n    type: parallel\n    parallel_mode:\n      max_parallel_builds: 3\n      check_mergeability_to_queue: true\n      override_required_checks: &#91;]\n      require_all_draft_checks_pass: true\n  merge_strategy:\n    name: squash<\/code><\/pre>\n\n\n\n<p>Just like above, create a new stacked branch and push it to your remote repository. Sync your stacked branches with the main to catch conflicts early:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>git fetch origin main\nav stack sync --rebase-to-trunk\nav stack push<\/code><\/pre>\n\n\n\n<p>Once the stack is ready to merge, you can post a GitHub comment on the PR at the top of your stack to merge the entire stack:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/aviator stack merge<\/code><\/pre>\n\n\n\n<p>Aviator MergeQueue start the validation and eventually merges all stacked PRs once validation is complete.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Deployments and Rollbacks<\/strong><\/h3>\n\n\n\n<p>Despite frequent commits and testing, merge conflicts and dependency errors can occur. A reliable rollback process is essential for main branch stability. Aviator Releases simplifies rollback management and quick fix deployment.<\/p>\n\n\n\n<p><a href=\"https:\/\/docs.aviator.co\/releases-beta\" title=\"\">Aviator Releases<\/a> provides centralized release management, organizing deployment pipelines and automating version control. Teams can manage rollbacks, cherry-pick changes, and implement strategies like canary releases and blue-green deployments from one platform.<\/p>\n\n\n\n<p>Aviator&#8217;s integration with trunk-based development ensures main branch stability and smooth integration. Its tools for quick fixes, structured rollbacks, and advanced testing strategies help teams confidently manage software updates while minimizing risk.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Best Practices for TBD in Microservices<\/strong><\/h2>\n\n\n\n<p>Here are some the best practices that should be followed when working with trunk-based development.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Short-Lived Feature Branches: Keep Branches Short to Avoid Code Drift<\/strong><\/h3>\n\n\n\n<p>In trunk-based development, feature branches should be brief and minimal. This prevents significant divergence between main and feature branches. Extended feature branches risk becoming outdated and creating integration issues. Short feature branches allow developers to work on isolated changes and merge quickly, minimizing code drift and maintaining codebase consistency. Here&#8217;s an example demonstrating several main branch commits and two pull requests from feature-stacked branches.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"1024\" height=\"367\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/11\/branches-1024x367.png\" alt=\"\" class=\"wp-image-3168\" srcset=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/11\/branches-1024x367.png 1024w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/11\/branches-300x108.png 300w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/11\/branches-768x275.png 768w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/11\/branches.png 1258w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>This is how the commit graph looks like, and you can further improve these individual branches if required.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Incremental Code Reviews: Tips for Frequent, Small Reviews<\/strong><\/h3>\n\n\n\n<p>Regular review of small, incremental changes is preferable to reviewing completed large features. This speeds up the review process and enables early issue detection without development delays. Frequent commits facilitate regular code reviews, keeping changes small and manageable.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"213\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/11\/GitHub-PR-view-1024x213.png\" alt=\"\" class=\"wp-image-3169\" srcset=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/11\/GitHub-PR-view-1024x213.png 1024w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/11\/GitHub-PR-view-300x62.png 300w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/11\/GitHub-PR-view-768x159.png 768w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/11\/GitHub-PR-view-1536x319.png 1536w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/11\/GitHub-PR-view.png 1546w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>You can review these pull requests and make incremental changes. After committing new changes, sync all stacked PR branches with this av command:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>av stack sync --all<\/code><\/pre>\n\n\n\n<p>This command will sync all the branches which you are using for stacked PRs by rebasing them with their parent branches and pushing them to the remote repository.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Selective Testing in Pipelines<\/strong><\/h3>\n\n\n\n<p>Continuous integration is a key feature of Trunk-based development, running tests in the CI\/CD pipeline after each main branch commit.<\/p>\n\n\n\n<p>The GitHub actions workflow automates this pipeline. Tests trigger automatically when code is pushed to main or when pull requests are created. View test results in the GitHub repository&#8217;s action tab.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"216\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/11\/pipeline-1-1024x216.png\" alt=\"\" class=\"wp-image-3170\" srcset=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/11\/pipeline-1-1024x216.png 1024w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/11\/pipeline-1-300x63.png 300w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/11\/pipeline-1-768x162.png 768w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/11\/pipeline-1.png 1414w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Not every change requires running all tests. Selective testing reduces pipeline time by focusing on relevant tests only. This provides faster feedback and confirms new changes don&#8217;t break existing functionality, while avoiding pipeline overload.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Simple Reverts<\/h3>\n\n\n\n<p>In <a href=\"https:\/\/www.aviator.co\/blog\/trunk-based-development\/\" target=\"_blank\" rel=\"noopener\" title=\"trunk based development\">trunk based development<\/a>, simple reverts maintain stability when issues arise despite continuous integration. Quick reversion of problematic changes in the trunk branch enables fast recovery. Automated rollbacks and clear procedures prevent minor issues from disrupting development. Small, isolated commits simplify error identification during reverts.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Ensuring Backward Compatibility: Strategies to Ensure Compatibility<\/strong><\/h3>\n\n\n\n<p>In microservices, backward compatibility is essential for service interactions. API and data contract versioning ensures older services can communicate with newer versions. Trunk-based development feature toggles enable incremental deployment, allowing production testing of new features while maintaining compatibility. This approach enables smooth system updates without disrupting existing functionality.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Efficient Deployment in Microservices<\/strong><\/h3>\n\n\n\n<p>Trunk-based development requires stable deployments with minimal downtime and quick rollback capabilities. Continuous deployment integrates naturally, delivering recent changes to staging or production. Blue-green deployments and canary releases enable gradual deployment, minimizing risk and facilitating rollbacks. Trunk-based development feature toggles allow partial deployment while maintaining system stability.<\/p>\n\n\n\n<p>Immutable infrastructure and monitoring systems support efficient deployments and rapid recovery. Standard APIs and backward compatibility reduce service coupling, enabling smooth system-wide updates.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>Trunk-based development multiple environments are ideal for stable, frequent updates. By focusing on small, frequent commits to the main branch, TBD minimizes merge conflicts and maintains codebase stability. This approach eliminates bottlenecks from isolated branches or complex branching strategies, enabling real-time service evolution through continuous updates. In microservices architecture, TBD&#8217;s continuous integration helps maintain service alignment and interaction, creating an efficient workflow that promotes code quality and rapid delivery.<\/p>\n\n\n\n<p>Short-lived feature branches and quick fixes enhance TBD&#8217;s benefits without adding overhead. Tools like <strong>Aviator&#8217;s av CLI<\/strong> help manage stacked pull requests, allowing developers to focus on clear, incremental changes that preserve main branch stability. Automated testing and continuous integration verify each commit before merging, enabling early bug detection and resolution. TBD empowers teams to make gradual improvements while avoiding complex merges and long-lived branch risks, making it ideal for dynamic, collaborative projects requiring reliable scaling.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/github.com\/aviator-co\/av\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"538\" src=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/07\/stackedPRs-linkedin-ad-1200x630-1-1024x538.png\" alt=\"\" class=\"wp-image-2368\" srcset=\"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/07\/stackedPRs-linkedin-ad-1200x630-1-1024x538.png 1024w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/07\/stackedPRs-linkedin-ad-1200x630-1-300x158.png 300w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/07\/stackedPRs-linkedin-ad-1200x630-1-768x403.png 768w, https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/07\/stackedPRs-linkedin-ad-1200x630-1.png 1200w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>FAQs<\/strong><\/h2>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>What Is Trunk-Based Development?<\/strong><\/h3>\n\n\n\n<p>Trunk-based development is a version control management practice where developers merge small, frequent updates to a core \u201ctrunk\u201d or main branch. Since it streamlines merging and integration phases, it helps achieve CI\/CD and increases software delivery and organizational performance.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>How Does Trunk-Based Development Differ from Traditional Git Workflows?<\/strong><\/h3>\n\n\n\n<p>Trunk-based development differs from traditional Git workflows like feature branching and GitFlow by focusing on a single main branch for all development. Developers commit changes directly to the main branch in small, frequent updates, as opposed to working in long-lived feature branches. This encourages faster integration and reduces the risk of merge conflicts, ensuring a more stable and quickly evolving codebase.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>What Are Some Best Practices for Managing Dependencies in TBD?<\/strong><\/h3>\n\n\n\n<p>In trunk-based development, managing dependencies is crucial to prevent bottlenecks. Best practices include using dependency management tools to lock versions and ensure compatibility, and avoiding tightly coupling services in a way that requires frequent changes across services. Additionally, keeping dependencies up to date with automated pipelines and minimizing direct dependencies between services helps maintain flexibility and speed.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>What Is the Difference Between Feature-Based and Trunk-Based Development?<\/strong><\/h3>\n\n\n\n<p>Feature-based development involves working on separate branches for individual features, often for extended periods before merging them into the main branch. This can lead to integration challenges and conflicts when merging. In contrast, trunk-based development encourages developers to commit small changes directly to the main branch, resulting in continuous integration. This minimizes the risks of code drift and merge conflicts, enabling faster releases and a more stable codebase.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Does Google Use Trunk-Based Development?<\/strong><\/h3>\n\n\n\n<p>The development workflows are also mainly Git-based. Two of the most widely used workflows are feature-based and trunk-based development (aka TBD). Software development teams at Netflix, Google, Facebook, and other tech giants use these workflows.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Trunk-based development helps achieve continuous delivery and improve developer experience. But it requires using the right tools and processes.<\/p>\n","protected":false},"author":38,"featured_media":3020,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[78],"tags":[113,93],"class_list":["post-2989","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-monorepo"],"blocksy_meta":[],"acf":[],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/www.aviator.co\/blog\/wp-content\/uploads\/2024\/11\/Copy-of-3-Factors-that-Comparison-of-Tools1.png","post_mailing_queue_ids":[],"_links":{"self":[{"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/posts\/2989","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/users\/38"}],"replies":[{"embeddable":true,"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/comments?post=2989"}],"version-history":[{"count":14,"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/posts\/2989\/revisions"}],"predecessor-version":[{"id":4369,"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/posts\/2989\/revisions\/4369"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/media\/3020"}],"wp:attachment":[{"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/media?parent=2989"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/categories?post=2989"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.aviator.co\/blog\/wp-json\/wp\/v2\/tags?post=2989"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}