<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Kyle Johnson</title>
    <description>The latest articles on DEV Community by Kyle Johnson (@kylessg).</description>
    <link>https://dev.to/kylessg</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2948%2F8608314.jpeg</url>
      <title>DEV Community: Kyle Johnson</title>
      <link>https://dev.to/kylessg</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kylessg"/>
    <language>en</language>
    <item>
      <title>Five Open Source tools to track your PostgreSQL database performance</title>
      <dc:creator>Kyle Johnson</dc:creator>
      <pubDate>Tue, 28 Jan 2025 14:34:32 +0000</pubDate>
      <link>https://dev.to/flagsmith/five-open-source-tools-to-track-your-postgresql-database-performance-3gki</link>
      <guid>https://dev.to/flagsmith/five-open-source-tools-to-track-your-postgresql-database-performance-3gki</guid>
      <description>&lt;p&gt;Written by Eddie Jaoude (see outro)&lt;/p&gt;

&lt;p&gt;How is your PostgreSQL (aka Postgres) database performing in production after releasing that latest shiny new feature? If you don’t measure its performance then you will never know and the best you can hope for is an educated guess. Do you want to rely on guesswork to decide whether you should be rolling out this new feature to your users? &lt;/p&gt;

&lt;p&gt;In this blog post I will take you through the steps to achieve/create a dashboard that monitors a PostgreSQL database. The dashboard will also be annotated when we enable/disable features. This is an effective way of monitoring the impact that enabling a new feature has on a database. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0htmsw97xq9hyvwq6chx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0htmsw97xq9hyvwq6chx.png" alt="Using Grafana with Flagsmith" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All tools that I refer to in this blog post are Open Source and free:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;NextJS for our app &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;https://nextjs.org/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PostgreSQL as our database &lt;a href="https://www.postgresql.org/" rel="noopener noreferrer"&gt;https://www.postgresql.org/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PostgreSQL Exporter to expose metrics -&lt;a href="https://github.com/prometheus-community/postgres_exporter" rel="noopener noreferrer"&gt;https://github.com/prometheus-community/postgres_exporter&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Prometheus to collect metrics &lt;a href="https://prometheus.io/" rel="noopener noreferrer"&gt;https://prometheus.io/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Grafana to display metrics &lt;a href="https://grafana.com/" rel="noopener noreferrer"&gt;https://grafana.com/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Flagsmith for feature flag management &lt;a href="https://www.flagsmith.com/" rel="noopener noreferrer"&gt;https://www.flagsmith.com/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;So that you can follow along please make sure that you have the following: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;Flagsmith (I will use their free cloud account, but you can also host it yourself on Docker).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;I will be using the following architecture setup, however you can move any items between any of the layers to better suit your situation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Host machine&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Our Application (NextJS)&lt;/li&gt;
&lt;li&gt;K6 to simulate users&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Docker&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;PostgreSQL database&lt;/li&gt;
&lt;li&gt;PostgreSQL Exporter&lt;/li&gt;
&lt;li&gt;Prometheus&lt;/li&gt;
&lt;li&gt;Grafana&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Cloud&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Flagsmith (you can run this in Docker if you prefer)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F941fqsyy1gbjfsndafqa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F941fqsyy1gbjfsndafqa.png" alt="Architecture Diagram" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  PostgreSQL
&lt;/h2&gt;

&lt;p&gt;For this blog I will be using the SQL database Postgres. Postgres is a popular Open Source relational database that is super robust and stable with decades of experience. I find it has a great balance of the latest trending features without compromising stability. I have used Postgres in projects for startups to UK banks, and it handles a variety of different data and performance situations without skipping a beat. &lt;/p&gt;

&lt;p&gt;If you already have a PostgreSQL database then please feel free to skip this section.&lt;/p&gt;

&lt;p&gt;This Docker command will create a PostgreSQL 14 database. Set the username and password as well as expose the port on our local machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--name&lt;/span&gt; postgres14 &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;user &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;password &lt;span class="nt"&gt;-p&lt;/span&gt; 5432:5432 &lt;span class="nt"&gt;-d&lt;/span&gt; postgres:14
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a small private network for all our Docker containers to communicate together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker network create postgres-network
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add the new PostgreSQL database to this private network. This is achieved by using the container name we created before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker network connect postgres-network postgres14
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you can inspect the network to get the PostgreSQL database’s IP with this command and specify the name of the network to inspect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker network inspect postgres-network
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the JSON output there will be a “Container” section that lists the containers in the network and also their respective IP. You will need the PostgreSQL IP in the next section.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"Containers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"4469e0602d83ac7fa2bd70ecbbcb34c41911cc342506c0f0a67f71365a61d54a"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"postgres14"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"EndpointID"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"5c8a26405db3598f472e9dcb4217b7b0f1d117974a5e2981e301bcda850a99e1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"MacAddress"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"02:42:ac:12:00:04"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"IPv4Address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"172.18.0.2/16"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"IPv6Address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  PostgreSQL Exporter
&lt;/h2&gt;

&lt;p&gt;Now we have a database, we need to get the performance metrics out from it. The PostgreSQL Exporter is the industry standard way to gather PostgreSQL metrics for Prometheus consumption. It is a stable project that has been around for many years and is still getting new features added all the time. At the time of writing this “Multi-Target Support” has been added as a beta feature. With plenty of content and use cases out there, you will not be short of examples to match your situation.&lt;/p&gt;

&lt;p&gt;To get the Docker container running we need to pass some more parameters. In addition to the Docker container name and exposing the port, specify the PostgreSQL database IP (you can get this from the end of the previous section using the Docker inspect command), the PostgreSQL database username and password.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run --name postgres-exporter -p 9187:9187 -e DATA_SOURCE_URI="172.18.0.2:5432/postgres?sslmode=disable" -e DATA_SOURCE_USER=user -e DATA_SOURCE_PASS=password -d quay.io/prometheuscommunity/postgres-exporter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As before, add the new container to the private Docker network with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker network connect postgres-network postgres-exporter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test the PostgreSQL Exporter is working by visiting this url in the browser or using curl on your host machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl "http://localhost:9187/metrics"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can learn more about the PostgreSQL Exporter in their GitHub repository &lt;a href="https://github.com/prometheus-community/postgres_exporter" rel="noopener noreferrer"&gt;https://github.com/prometheus-community/postgres_exporter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next inspect the private network again for the PostgreSQL Exporter IP, as this will be needed in the following section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker network inspect postgres-network
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Prometheus
&lt;/h2&gt;

&lt;p&gt;At this stage we have a database and we have the performance metrics, but we need to store the collected data over time. Prometheus is the go to Open Source tool for “metrics to insight” built with monitoring and alerting in mind. It stores the data in a time series format and has many integrations with popular tools and platforms. With great documentation, an active GitHub repo (50k+ Stars), and a large community, it is no surprise that Prometheus is the go to tool.&lt;/p&gt;

&lt;p&gt;Although Prometheus has a big ecosystem it is straightforward to get started. All we will need is a small YAML file and one Docker command.&lt;/p&gt;

&lt;p&gt;Create a YAML file called “prometheus.yml”. You can keep this anywhere you prefer, but I have chosen to do so in my “Downloads” folder (full path “~/Downloads/prometheus.yml”).&lt;/p&gt;

&lt;p&gt;In this file, first set global configs for “scrape_interval” and “evaluation_interval”. Note these global configs can be overwritten at the job level if required when having multiple jobs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;scrape_interval&lt;/strong&gt;: defines how often the monitor is scraped - you can change this to your preference, I have selected 15 seconds here.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;evaluation_interval&lt;/strong&gt;: defines how often queries are evaluated for alerting.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is recommended in most cases to have both these global configs set at the same value.&lt;/p&gt;

&lt;p&gt;Below the global configs, we specify the jobs under “scrape_configs”, this is made up of the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;job_name&lt;/strong&gt;: you can call this the name you prefer, it will show in your Prometheus web page of targets (screenshot below)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;static_configs&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;targets&lt;/strong&gt;: this is the IP and port to scrape of the “Postgres Exporter” in this example. Use the IP from the last Docker command in the previous section.
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;global&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;scrape_interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;15s&lt;/span&gt;
  &lt;span class="na"&gt;evaluation_interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;15s&lt;/span&gt;

&lt;span class="na"&gt;scrape_configs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;job_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;postgres-exporter"&lt;/span&gt;
    &lt;span class="na"&gt;static_configs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;targets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;172.18.0.3:9187"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now to run the Prometheus Docker container to use the YAML config file just created:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; prometheus &lt;span class="nt"&gt;-p&lt;/span&gt; 9090:9090 &lt;span class="nt"&gt;-v&lt;/span&gt; ~/Downloads/prometheus.yml:/etc/prometheus/prometheus.yml &lt;span class="nt"&gt;-d&lt;/span&gt; prom/prometheus
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last step in this section is to add our new Prometheus container to the private network we created. Use the following command to do this is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker network connect postgres-network prometheus
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then visit &lt;a href="http://localhost:9090/targets" rel="noopener noreferrer"&gt;http://localhost:9090/targets&lt;/a&gt; and you will see the job and the state of “UP”:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgkn8eub0efo82u92q3e4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgkn8eub0efo82u92q3e4.png" alt="Prometheus targets" width="800" height="231"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note: If you stop the Prometheus container, it will no longer have access to the private network. Therefore you will need to add it back to the network created so it has access to the other containers. If you have restarted other containers also check none of their container IPs have changed, as these might need updating in the config files and also network.&lt;br&gt;
You can also learn more about Prometheus on their official website: &lt;a href="https://prometheus.io/docs/introduction/overview/" rel="noopener noreferrer"&gt;https://prometheus.io/docs/introduction/overview/&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Grafana
&lt;/h2&gt;

&lt;p&gt;Now we have our Postgres performance metrics stored, we need to visualise the data. Grafana visualises, queries and alerts on our data from multiple sources including Prometheus as well as NoSQL/SQL databases. With Grafana being so popular and customizable, it has a large community with pre-existing templates to kickstart our Grafana dashboard and then we can customize as needed.&lt;/p&gt;

&lt;p&gt;Grafana can run on Docker with one command, which uses port 3000. I will map this externally to port 3001 on my host machine because my NextJS is already using port 3000:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 3001:3000 &lt;span class="nt"&gt;--name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;grafana grafana/grafana-enterprise
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the new container to our network:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker network connect postgres-network grafana
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visit the Grafana Dashboard &lt;a href="http://localhost:3001" rel="noopener noreferrer"&gt;http://localhost:3001&lt;/a&gt; in the browser. You can log in with the username “admin” and the password “admin” - you will be prompted to update the password, but if running Grafana locally you can click the “skip” button for now.&lt;/p&gt;

&lt;p&gt;Firstly open the side menu and expand “Connections” and click “Data source”. Then you can click “Add data source” for Prometheus.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmr5fi1ry7rfakwewu7dd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmr5fi1ry7rfakwewu7dd.png" alt="Grafana data sources" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsdd7w1o4t840zojwhi2k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsdd7w1o4t840zojwhi2k.png" alt="Grafana add Data source" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select Prometheus and you will need to add the Prometheus URL. You can get the IP by inspecting the Docker network again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker network inspect postgres-network
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frjvb14yt74tvqe5uk1id.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frjvb14yt74tvqe5uk1id.png" alt="Prometheus container" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Only the Prometheus URL is required (don’t forget to add the port). The other fields are optional and can be updated later if required:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8bsg47iagiuznhq7fmit.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8bsg47iagiuznhq7fmit.png" alt="Prometheus connection" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now there is a data source, a great place to start a Grafana Dashboard is from an existing template and customise it further from there. &lt;/p&gt;

&lt;p&gt;Visit your Grafana Dashboard on &lt;a href="http://localhost:3001/dashboard/import" rel="noopener noreferrer"&gt;http://localhost:3001/dashboard/import&lt;/a&gt; and paste in the templated Grafana Dashboard URL &lt;a href="https://grafana.com/grafana/dashboards/455-postgres-overview/" rel="noopener noreferrer"&gt;https://grafana.com/grafana/dashboards/455-postgres-overview/&lt;/a&gt; and then click “load”. A new form will appear and you can rename the dashboard, but the important part is to select a Prometheus source.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzyii5yme8a6tozdmmrhc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzyii5yme8a6tozdmmrhc.png" alt="Import Prometheus dashboard" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My imported Grafana Dashboard looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjpx152q6ivdz6iq8dkwh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjpx152q6ivdz6iq8dkwh.png" alt="Grafana Dashboard" width="800" height="671"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;List your running Docker containers with this command and you should see the following containers running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu4phklinxbbupnzohc82.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu4phklinxbbupnzohc82.png" alt="Docker ps" width="800" height="74"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to read more about Grafana then check out their website: &lt;a href="https://grafana.com/docs/grafana/latest/" rel="noopener noreferrer"&gt;https://grafana.com/docs/grafana/latest/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Flagsmith
&lt;/h2&gt;

&lt;p&gt;We have all been there where our project needs some feature flags and we think we are being smart by moving them to a config file or environment variable. In reality we still need to deploy to make changes and the developers/devops in the team will need to make those changes. Plus they are not instant and usually require a full redeploy. &lt;/p&gt;

&lt;p&gt;To manage my feature flags, I don’t like to reinvent the wheel, so I use the Open Source project Flagsmith and their cloud platform. Flagsmith has more features than I could ever create, plus it allows me to ship faster and more confidently by decoupling my deployments and releases as well as other great features that allow me to release to specific users or groups of users before everyone.&lt;/p&gt;

&lt;p&gt;With Flagsmith we can not only toggle this feature on/off but we can also expose it to specific people or groups of people.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sign up
&lt;/h3&gt;

&lt;p&gt;First start by signing up to Flagsmith's free account &lt;a href="https://www.flagsmith.com/" rel="noopener noreferrer"&gt;https://www.flagsmith.com/&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Once you sign up / log in, you will create an “Organisation” and then a “Project”:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F27lpnfor3nhs9i6yzr9w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F27lpnfor3nhs9i6yzr9w.png" alt="Flagsmith Project" width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a feature flag
&lt;/h2&gt;

&lt;p&gt;Click the “Create Feature” button at the top right.&lt;br&gt;
Give the feature a name. One thing to take into consideration is that you cannot change the name later.&lt;br&gt;
Leave “Enabled by default” off.&lt;/p&gt;

&lt;p&gt;“Value” is not needed for our feature as we will use enable/disable only. Value would be used for controlling the content. For example when to show a banner and the content of the banner.&lt;br&gt;
You can also give a “Description”, but note that you can change this later.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzx6zes52psxfhudgxk2b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzx6zes52psxfhudgxk2b.png" alt="Create a feature flag in Flagsmith" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Create a feature flag
&lt;/h2&gt;

&lt;p&gt;Flagsmith has many integrations so do make sure that you check out their great documentation. &lt;/p&gt;

&lt;p&gt;To use Flagsmith with NextJS, add it as an npm dependency with the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i flagsmith &lt;span class="nt"&gt;--save&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a NextJS provider in file “src/app/providers.js”:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FlagsmithProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flagsmith/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createFlagsmithInstance&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flagsmith/isomorphic&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Providers&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;serverState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;flagsmithInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;createFlagsmithInstance&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FlagsmithProvider&lt;/span&gt;
      &lt;span class="nx"&gt;flagsmith&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;flagsmithInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;serverState&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;serverState&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/FlagsmithProvider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open the “src/app/layout.js” file and in the import section add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createFlagsmithInstance&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flagsmith/isomorphic&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Providers&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./Providers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then in the RootLayout function add (don’t forget to make the function async):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;flagsmith&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createFlagsmithInstance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;flagsmith&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;environmentID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_FLAGSMITH_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;serverState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;flagsmith&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;serverState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// just to check the data is coming through&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wrap the “body” in the provider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Providers&lt;/span&gt; &lt;span class="nx"&gt;serverState&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;serverState&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;inter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/body&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Providers&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly add your &lt;strong&gt;“NEXT_PUBLIC_FLAGSMITH_ID”&lt;/strong&gt; to the “.env” file, which you can find in the “SDK Keys” menu on the left of your Flagsmith Dashboard. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi3dnrdb6qqh8iwm08ypa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi3dnrdb6qqh8iwm08ypa.png" alt="Flagsmith SDK key" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your “.env” file should look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NEXT_PUBLIC_FLAGSMITH_ID=3C5QvbtgZ3C5Qvbxyz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s run the app and check it all works together as expected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There should be no visual change in the UI, but in the terminal there will be a further output from Flagsmith because of our &lt;code&gt;console.log&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In my terminal I have the following output which contains the feature flags I created in Flagsmith. (Currently I only have one feature flag, if there were more you would see them in the output also.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; ✓ Compiled &lt;span class="k"&gt;in &lt;/span&gt;101ms &lt;span class="o"&gt;(&lt;/span&gt;496 modules&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
  api: &lt;span class="s1"&gt;'https://edge.api.flagsmith.com/api/v1/'&lt;/span&gt;,
  environmentID: &lt;span class="s1"&gt;'3C5QvbtgZh3C5QvbtgZh'&lt;/span&gt;,
  flags: &lt;span class="o"&gt;{&lt;/span&gt;
    stats: &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="nb"&gt;id&lt;/span&gt;: 98466,
      enabled: &lt;span class="nb"&gt;false&lt;/span&gt;,
      value: &lt;span class="s1"&gt;''&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;,
  identity: undefined,
  ts: null,
  traits: &lt;span class="o"&gt;{}&lt;/span&gt;,
  evaluationEvent: null
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Use Feature Flag
&lt;/h2&gt;

&lt;p&gt;On my homepage, I am thinking of showing some near real-time statistics but I am concerned about the impact. By wrapping it in a Flagsmith Feature Flag, I can enable it for my user, a group of users or for everyone, as well as disable it if required. I have created a Stats component that I will include on the homepage, and in the Stats component it will check for the Feature Flag “stats” status.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useFlags&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flagsmith/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Stats&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;stats&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useFlags&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stats&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can show/hide these stats from the Flagsmith Dashboard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnuzofu3f28vheuvtkvv6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnuzofu3f28vheuvtkvv6.png" alt="View features in Flagsm9ith" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrate with Grafana
&lt;/h2&gt;

&lt;p&gt;It is important to know when we toggle on/off features in our app what the direct impact on the application’s performance is. Yes we could try and guess what happened when, but this is neither efficient nor accurate. It is much better to integrate Flagsmith with Grafana, so that it actually puts a marker (called a “Grafana Annotation”) on the graph for us.&lt;/p&gt;

&lt;p&gt;The integration is straightforward. However we need to expose our Grafana instance to the internet so Flagsmith in the cloud can communicate with it. &lt;/p&gt;

&lt;p&gt;If you are not using Flagsmith cloud and your Flagsmith instance is local to your Grafana or your Grafana is on the internet already (because you are using Grafana cloud), then you can skip this section. &lt;/p&gt;

&lt;p&gt;There are multiple ways to achieve this, but my preferred way is to use an npm package which results in a total of using two commands:&lt;/p&gt;

&lt;p&gt;Install the npm package “localtunnel” globally with the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; localtunnel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tell localtunnel what port to expose to the internet and forward to my local instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lt &lt;span class="nt"&gt;--port&lt;/span&gt; 3001
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will return us a URL that can be used for the integration on Flagsmith.It is therefore important to remember this URL as it will be needed for the next step on the Flagsmith’s Dashboard.&lt;/p&gt;

&lt;p&gt;Get a “service account token” from your Grafana.This can be done by opening the side menu and clicking “Users and access”, then “Service accounts”. Then give the service account a name.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6mckz1zqe00egvb4pidj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6mckz1zqe00egvb4pidj.png" alt="Grafana create service account" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the newly created service account, create a token.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuxmoept3tf7ajxlvtflv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuxmoept3tf7ajxlvtflv.png" alt="Create Grafana service account token" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy this token to your clipboard as you will need it in the next step on the Flagsmith Dashboard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy2crva2tva7ybor83yb6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy2crva2tva7ybor83yb6.png" alt="Copy Grafana service account token" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go to the Flagsmith Dashboard and click on “Integrations”:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkgnsywcbec0cr1qfk30w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkgnsywcbec0cr1qfk30w.png" alt="Flagsmith integrations" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then scroll down to “Grafana” and click on “Add Integration”. Add the URL that was generated in the terminal and the “service account token” previously copied.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi43jhn28qbqwcl9lu49a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi43jhn28qbqwcl9lu49a.png" alt="Create Grafana integration in Flagsmith" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you will see the integration is complete.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9q75aqzr4emwev1ieitt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9q75aqzr4emwev1ieitt.png" alt="Grafana integration in Flagsmith" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The final step is to display the Flagsmith feature flag changes on the Grafana Dashboard. We will need to edit the Grafana Dashboard we imported earlier to add the annotation as it occurs. &lt;/p&gt;

&lt;p&gt;Go back to the Grafana Dashboard created earlier and press “Edit”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Friyli67d8ig7xip6w23n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Friyli67d8ig7xip6w23n.png" alt="Edit Grafana Dashboard" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the Grafana Dashboard settings click the “Annotations” tab and then “Add annotation query”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftm4jk0bcdgnvvm3sh7e3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftm4jk0bcdgnvvm3sh7e3.png" alt="Grafana annotations" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Give the annotation a name and select “Grafana” for the data source. For the filter drop down select “Tags” and select the tags you are interested in - I selected my whole Flagsmith project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6z8zhh96mqj2yw5w9xjz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6z8zhh96mqj2yw5w9xjz.png" alt="Create Flagsmith Grafana annotation" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Save the annotation changes to the Grafana Dashboard and exit edit mode, returning to the main Grafana Dashboard view. You will now have a “Flagsmith” toggle at the top of the Grafana Dashboard to show/hide the annotations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fddutvvo3lmcqboauozts.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fddutvvo3lmcqboauozts.png" alt="Grafana Flagsmith toggle" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this toggle enabled, each time changes are made on the Flagsmith Dashboard they will appear on the Grafana Dashboard. I will demonstrate this shortly but first, I will generate some user load to make the graphs more interesting.&lt;/p&gt;

&lt;h2&gt;
  
  
  k6
&lt;/h2&gt;

&lt;p&gt;Simulating and creating user traffic can be tricky. There are many tools out there and I have tried and used many over the years. Recently I came across k6. This is a load testing tool created by Grafana. It is designed to be developer friendly, from browser performance testing to chaos and resilience testing. k6 has packages for the popular operating systems as well as a Docker container and a standalone binary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;p&gt;I will install k6 on my Mac with brew:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;k6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Script
&lt;/h3&gt;

&lt;p&gt;In k6’s Getting Started guide, they have some great example scripts to get started. I have taken their “Ramp VUs up and down in stage” and modified them a little for my needs.&lt;/p&gt;

&lt;p&gt;The script has the imports at the top as you would expect, followed by the test configuration. In the configuration there are an array of “stages” where each item is an object of “duration” and “target”. In this “stages” array you can ramp up and down the users at specific times.&lt;/p&gt;

&lt;p&gt;After exporting the config options, export a default function with the URL k6 will make the request against and then validate the response, in this case we are expecting a status code of 200.&lt;/p&gt;

&lt;p&gt;I will add the following k6 script to a file called “script.js” in the root of the project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;k6/http&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;check&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sleep&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;k6&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Test configuration&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;thresholds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Assert that 99% of requests finish within 3000ms.&lt;/span&gt;
    &lt;span class="na"&gt;http_req_duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;p(99) &amp;lt; 3000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;// Ramp the number of virtual users up and down&lt;/span&gt;
  &lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;30s&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1m&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;3m&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;20s&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Simulated user behavior&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Validate response status&lt;/span&gt;
  &lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;status was 200&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To run the above k6 script, use the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;k6 run script.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output is:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdyzj9cod99kosbv4g2pk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdyzj9cod99kosbv4g2pk.png" alt="k6 Output" width="800" height="516"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While k6 is running, we can toggle our Flagsmith feature on/off and see the effect it has on the application. Each time changes on the Flagsmith’s Dashboard are made the annotation appears and we can hover the annotating line to get more information.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk01e545qvmua96triltq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk01e545qvmua96triltq.png" alt="Flagsmith annotations" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you can test in production and make an informed decision as to whether you should roll out the new feature to everyone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Troubleshooting
&lt;/h2&gt;

&lt;p&gt;You might find yourself having connection issues between the containers during setup. Or the setup initially worked but after restarting one or more containers or your host machine, it no longer works. I found that this is usually due to IP changes, which caught me out multiple times before. &lt;/p&gt;

&lt;p&gt;Note that you might not get any visible errors in the logs, but no data will be coming through the workflow. Check the IP of each container and make sure it is in the private network and the relative YAML config files are updated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;What effect does your latest feature have on your app’s health? If you can’t quantify the impact, how do you know if you should or should not roll it out to all your users? There is no need to build scripts and tooling to capture then measure the performance of your app before and after changes. This is complex and time consuming, especially when you could be using this time to focus on your app. There are so many Open Source tools that you can use and integrate together to help you measure performance and improve your product, allowing you to focus on what you can deliver and the benefits to your users. Plus if you don’t want to host and manage these tools most of them have cloud versions you can also use.&lt;/p&gt;

&lt;p&gt;Having a strong foundation for your project will help you make more informed decisions rather than guessing. &lt;/p&gt;

&lt;p&gt;When you find yourself in the situation when something happened to your production app and you are trying to understand the “how” and “why” while debugging the situation, if you have not captured the historic information, then this becomes very difficult. &lt;/p&gt;

&lt;p&gt;Key takeaways: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;1: You can’t improve what you don’t measure. Measure before and after the changes so you can compare the impact these changes have on your project.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;2: Be proactive. Simulate user load and see how your product performs; one user is different to 1000 users.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;3: Use feature flags to safely and confidently test in production without affecting your users, which will allow you to make more accurate decisions.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Be proactive with all your changes, know the impact, and be confident to deploy on a Friday!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;About the Author&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Eddie is passionate about technologies and products which contribute towards a developer's work becoming more efficient and high quality.&lt;/p&gt;

&lt;p&gt;Eddie uses his 15+ years of Fullstack expertise to offer personalised consulting on Open Source best practices, as well as creating technical content to bring awareness, review and teach his clients' latest products and services, to the tech community. To name a few areas, Eddie has a keen interest in Javascript/Typescript, API, databases and DevOps.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.eddiejaoude.io/" rel="noopener noreferrer"&gt;https://www.eddiejaoude.io/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://eddiejaoude.substack.com/links" rel="noopener noreferrer"&gt;http://eddiejaoude.substack.com/links&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>grafana</category>
      <category>flagsmith</category>
      <category>prometheus</category>
    </item>
    <item>
      <title>Implementing Feature Flags with Next.js and App Router</title>
      <dc:creator>Kyle Johnson</dc:creator>
      <pubDate>Thu, 02 Nov 2023 16:33:00 +0000</pubDate>
      <link>https://dev.to/kylessg/implementing-feature-flags-with-nextjs-and-app-router-1gl8</link>
      <guid>https://dev.to/kylessg/implementing-feature-flags-with-nextjs-and-app-router-1gl8</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this article we will discuss how we can combine the power of Vercel and feature flags (&lt;a href="https://www.flagsmith.com/" rel="noopener noreferrer"&gt;Flagsmith&lt;/a&gt; - open source) to build and deploy a config controlled application from scratch in less than 15 minutes using Next.Js feature flags. Written with &lt;a href="https://dev.to/abhishekag03"&gt;Abhishek Agarawal&lt;/a&gt;🚀!&lt;/p&gt;

&lt;p&gt;Through this blog, we will learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The importance of feature flags&lt;/li&gt;
&lt;li&gt;How to create a basic Next.js application with Vercel Approuter&lt;/li&gt;
&lt;li&gt;Setting up Vercel and push the project to Vercel&lt;/li&gt;
&lt;li&gt;Deploy the application&lt;/li&gt;
&lt;li&gt;Add feature flags to it&lt;/li&gt;
&lt;li&gt;See real time changes on the website as we update feature flags from Flagsmith console&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;Vercel is developers’ favourite platform to develop, preview and ship any application. It makes building complex applications easier and much more efficient.&lt;/p&gt;

&lt;p&gt;Next.js is a popular open-source framework provided by Vercel and built on top of Node.js for building server-side rendered (SSR) React applications. Its core advantages include faster page loads, better SEO, and improved developer experience.&lt;/p&gt;

&lt;p&gt;Feature flags offer the power of managing features in production out of the box. We chose to integrate with Flagsmith (&lt;a href="https://github.com/Flagsmith/flagsmith" rel="noopener noreferrer"&gt;https://github.com/Flagsmith/flagsmith&lt;/a&gt;). The set-up and integration is seamless and provides enormous power with just the click of a few buttons.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Feature Flagging and Its Importance
&lt;/h2&gt;

&lt;p&gt;Feature flagging, also known as feature toggling or feature flipping, is a powerful software development technique that enables developers to deploy new features and changes to production in a controlled and gradual manner. Instead of releasing all changes at once, feature flags allow you to selectively enable or disable specific features for different segments of your user base.&lt;/p&gt;

&lt;p&gt;But why is this approach so valuable? There are several reasons why feature flagging has become an essential part of modern software development:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Reduced Deployment Risks&lt;/strong&gt;: Feature flagging reduces the risks associated with deploying new features. By gradually rolling out changes to a small subset of users, developers can closely monitor the impact and performance of the new features before making them available to a broader audience. This helps catch potential issues early and allows for quick adjustments if needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Continuous Delivery and Experimentation&lt;/strong&gt;: With feature flagging, you can continuously deliver updates and experiment with new features without causing disruptions to the entire user base. This enables agile development practices and encourages a culture of experimentation, where developers can test hypotheses and gather real-world data to inform their decisions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Personalized User Experiences&lt;/strong&gt;: By segmenting users based on various traits (e.g., profession, location, subscription type), you can provide personalized experiences tailored to different user groups. This allows you to deliver targeted content, A/B test different variations, and optimize user engagement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hotfixes and Rollbacks&lt;/strong&gt;: Feature flags provide a safety net for quick hotfixes and rollbacks. If a new feature causes unexpected issues or receives negative feedback, you can easily turn it off with a flag, avoiding the need for a full redeployment.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Integrating Flagsmith with Next.js
&lt;/h2&gt;

&lt;p&gt;In this guide, we've chosen Flagsmith as our feature flagging solution. Flagsmith is an &lt;a href="https://github.com/Flagsmith/flagsmith" rel="noopener noreferrer"&gt;open-source platform&lt;/a&gt; that offers a user-friendly interface for &lt;a href="https://www.flagsmith.com/feature-flags-and-remote-config" rel="noopener noreferrer"&gt;managing feature flags&lt;/a&gt;, &lt;a href="https://www.flagsmith.com/a-b-and-multivariate-testing" rel="noopener noreferrer"&gt;A/B testing&lt;/a&gt;, and &lt;a href="https://www.flagsmith.com/segmentation" rel="noopener noreferrer"&gt;segment overrides&lt;/a&gt;. You can control feature behaviour without modifying code, making it a powerful tool for managing complex projects with multiple feature variations.&lt;/p&gt;

&lt;p&gt;By integrating Flagsmith into our Next.js project deployed on Vercel, we gain the ability to perform phased rollouts, control feature visibility based on user segments, and dynamically change feature settings in real-time without redeploying the application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let’s start building!&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Flagsmith Account Setup
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;If you do not have an account already, visit &lt;a href="https://app.flagsmith.com/signup" rel="noopener noreferrer"&gt;https://app.flagsmith.com/signup&lt;/a&gt; and create a new account. Flagsmith also offers simple sign in with Google or Github options.&lt;/li&gt;
&lt;li&gt;Create an organisation. For the purpose of this tutorial I’ll name it “Flagsmith &amp;lt;-&amp;gt; Vercel”. Feel free to pick your own.&lt;/li&gt;
&lt;li&gt;Create a project inside this organisation by clicking “Create A Project''. I’ll just name it “my-nextjs-project”.&lt;/li&gt;
&lt;li&gt;Congrats! You have already completed the Flagsmith setup process. You should see a screen with instructions on how to create new features.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We will come back to this screen when we want to add Next.js feature flags to our application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Github repo setup
&lt;/h2&gt;

&lt;p&gt;Create a new repo on &lt;a href="https://github.com/" rel="noopener noreferrer"&gt;https://github.com/&lt;/a&gt;. I have named it “vercel-flagsmith-integration”. Feel free to rename it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vercel account setup&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Visit &lt;a href="https://vercel.com/signup" rel="noopener noreferrer"&gt;https://vercel.com/signup&lt;/a&gt; and you can easily signup with your Github account&lt;/li&gt;
&lt;li&gt;Create a New project by Clicking Add New -&amp;gt; Project. You can simply visit &lt;a href="https://vercel.com/new" rel="noopener noreferrer"&gt;https://vercel.com/new&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;On the home page, all the Github repos associated with the account should be visible. Make sure the access to read repos is granted. The recently created project should also be visible in the list. Vercel automatically detects that it is a Next.js project.&lt;/li&gt;
&lt;li&gt;We will import this project once we have added some code&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Now, let’s start coding 😀&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a starter Next.js project
&lt;/h2&gt;

&lt;p&gt;We will be using the &lt;code&gt;create-next-app&lt;/code&gt; CLI tool to build us a starter project. Reference - &lt;a href="https://nextjs.org/docs/api-reference/create-next-app" rel="noopener noreferrer"&gt;https://nextjs.org/docs/api-reference/create-next-app&lt;/a&gt; . On the top of this, I have added a basic login page, so that we can take some user input and toggle behaviour based on that in the next steps.&lt;/p&gt;

&lt;p&gt;We will be using the Vercel AppRouter paradigm for building our application.&lt;/p&gt;

&lt;p&gt;Clone this repo to view the code &lt;a href="https://github.com/abhishekag03/vercel-flagsmith-integration" rel="noopener noreferrer"&gt;https://github.com/abhishekag03/vercel-flagsmith-integration&lt;/a&gt;. Refer to the pull requests to understand the changes step by step. Specifically, &lt;a href="https://github.com/abhishekag03/vercel-flagsmith-integration/tree/1605d9645246eb7320e497f1e0e48670420a62b5" rel="noopener noreferrer"&gt;this state&lt;/a&gt; of the repo describes the current expectation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let’s deploy!
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Time to visit our Vercel dashboard again - &lt;a href="https://vercel.com/new" rel="noopener noreferrer"&gt;https://vercel.com/new&lt;/a&gt;. Click on the “Import” button next to the repository where you just pushed.&lt;/li&gt;
&lt;li&gt;Hit the “Deploy” button now&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After the deployment has completed (typically it should not take more than a couple of minutes), click on the preview screen which will take you to the deployed website. The DNS in this case is &lt;a href="https://vercel-flagsmith-integration.vercel.app/" rel="noopener noreferrer"&gt;https://vercel-flagsmith-integration.vercel.app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can visit the dashboard for your project (by clicking “Continue to Dashboard” in the above section) and view the domains and various other settings&lt;/p&gt;

&lt;p&gt;Now, any change that we push to the “main” branch of our repo will get deployed here in near real time!&lt;/p&gt;

&lt;p&gt;That’s how simple deploying applications with Vercel is!&lt;/p&gt;

&lt;h2&gt;
  
  
  Combining the power of Flagsmith with Vercel
&lt;/h2&gt;

&lt;p&gt;We already saw how easy it is to set up and deploy a Next.js project. This is good for a basic project - however, in most cases we want more control towards the application behaviour.&lt;/p&gt;

&lt;p&gt;For instance, imagine we want to add a new card to the below page. Currently it contains 4 cards - “Docs”, “Learn”, ‘Templates” and “Deploy”. Adding a new card is trivial, but for large applications, such changes are always rolled out incrementally. They are rolled out either based on geography, type or percentage basis. Building this incremental rollout functionality can be tricky as it involves managing a lot of variables with real time updates.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhk5a6utrah4nj8cegq9n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhk5a6utrah4nj8cegq9n.png" alt="NextJS Starting page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s where Flagsmith comes in. It offers a solution which allows you to manage all your Next.js feature flags, A/B testing and experimentation at one place with just the click of a button.&lt;/p&gt;

&lt;p&gt;We will see how easy it is to rollout a feature to a certain segment of users with Flagsmith.&lt;/p&gt;

&lt;p&gt;What we want is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;On visiting the site, user should have an option to type their name and choose their Profession&lt;/li&gt;
&lt;li&gt;Upon submitting, based on the user’s chosen profession, they should see the next screen.&lt;/li&gt;
&lt;li&gt;The screen behaviour based on professions should be controlled from the Flagsmith console.&lt;/li&gt;
&lt;li&gt;Change the list of professions dynamically on Flagsmith console and see realtime updates on our website&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Integrating Flagsmith with Next.js Application
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Add dependencies
&lt;/h3&gt;

&lt;p&gt;We need to first add the flagsmith package. Run the below command: \&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npm i flagsmith &lt;span class="nt"&gt;--save&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Initialise the Flagsmith client
&lt;/h3&gt;

&lt;p&gt;Now, we need to add code to initialise the flagsmith client.&lt;/p&gt;

&lt;p&gt;TL;DR - &lt;a href="https://github.com/abhishekag03/vercel-flagsmith-integration/pull/9" rel="noopener noreferrer"&gt;Pull Request&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since we want the flagsmith features to be loaded and present in the state, we will create a provider file which handles loading the flag state and supplying it to our app pages. This allows us to use the FlagsmithProvider.&lt;/p&gt;

&lt;p&gt;Thus, create a file named  &lt;code&gt;app/provider.tsx&lt;/code&gt;. The content inside it should be as follows:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;flagsmith&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flagsmith/isomorphic&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FlagsmithProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flagsmith/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;IState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flagsmith/types&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ReactElement&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;flagsmithState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flagsmithState&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;IState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FlagsmithProvider&lt;/span&gt; &lt;span class="nx"&gt;flagsmith&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;flagsmith&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;serverState&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;flagsmithState&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ReactElement&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/FlagsmithProvider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The Flagsmith provider will allow all of its child components to access feature flags via the &lt;a href="https://docs.flagsmith.com/clients/react#step-2-using-useflags-to-access-feature-values-and-enabled-state" rel="noopener noreferrer"&gt;useFlags&lt;/a&gt; hook. In our example, we will fetch these flags from the server and pass them to the provider via the serverState property.&lt;/p&gt;

&lt;p&gt;We will be importing this provider inside our &lt;code&gt;app/layout.tsx file&lt;/code&gt;. This is also the place where we call the init function for getting Flagsmith feature flag state.&lt;/p&gt;

&lt;p&gt;Add the 2 imports as shown below:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Provider&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./provider&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;flagsmith&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flagsmith/isomorphic&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;RootLayout&lt;/code&gt; in the &lt;code&gt;app/layout.tsx&lt;/code&gt; file needs to updated as shown below:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;RootLayout&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;flagsmithState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;flagsmith&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="c1"&gt;// fetches flags on the server&lt;/span&gt;
      &lt;span class="na"&gt;environmentID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;heiEFz5x78igSLA8fGRgiP&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// substitute your env ID&lt;/span&gt;
      &lt;span class="na"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my_user_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// specify the identity of the user to get their specific flags&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;flagsmith&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Provider&lt;/span&gt; &lt;span class="nx"&gt;flagsmithState&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;flagsmithState&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ReactElement&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Provider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/body&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/html&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Remember to substitute your env specific environmentID in the layout.tsx file&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To get the environmentID, navigate back to the flagsmith website.&lt;/p&gt;

&lt;p&gt;Click on “Settings” for your environment, then click “Keys”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxrsfhnfccolusavd385w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxrsfhnfccolusavd385w.png" alt="Flagsmith SDK Key"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ensure that you are still able to successfully run the application by running:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

yarn dev


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Create a new card for the about page
&lt;/h3&gt;

&lt;p&gt;As described in the agenda, we will add a new Card. This is the card that we intend rolling out in a phased manner based on user profession / segment.&lt;/p&gt;

&lt;p&gt;TL;DR: &lt;a href="https://github.com/abhishekag03/vercel-flagsmith-integration/pull/10" rel="noopener noreferrer"&gt;Pull request&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The below code can be added to the Page() function inside &lt;code&gt;app/about/Page.tsx&lt;/code&gt; file to get this new card.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;
  &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://vercel.com/new?utm_source=create-next-app&amp;amp;utm_medium=default-template&amp;amp;utm_campaign=create-next-app&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_blank&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;rel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;noopener noreferrer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;inter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;Configure&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;-&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;gt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;inter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;Configure&lt;/span&gt; &lt;span class="nx"&gt;your&lt;/span&gt; &lt;span class="nx"&gt;feature&lt;/span&gt; &lt;span class="nx"&gt;rollout&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;nbsp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="nx"&gt;Flagsmith&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/a&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Once this code is merged and deployed, this change will be visible to all the users who visit our website.&lt;/p&gt;

&lt;p&gt;However, &lt;strong&gt;that’s not what we want.&lt;/strong&gt; As a principal, new features are added incrementally. What if the Configure link was broken? What if there was an issue in the flow inside the configure? What if user’s have started hating the Configure card and we want to remove it?&lt;/p&gt;

&lt;p&gt;What if I told you all this control is possible with just a single click?&lt;/p&gt;

&lt;p&gt;Let’s add a phased rollout mechanism, so that only users with the profession “Freelancer” are shown this card first.&lt;/p&gt;

&lt;p&gt;For this, we need to add a new feature on the Flagsmith dashboard.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a Feature
&lt;/h3&gt;

&lt;p&gt;Click on “Create Your First Feature” option below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxcm4ttewxun4859jhbal.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxcm4ttewxun4859jhbal.png" alt="Creating a feature in Flagsmith"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’m naming the feature “configure_card_controller” since it controls the card named “Configure”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj3p60b1nf10psqfi7hc2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj3p60b1nf10psqfi7hc2.png" alt="Creating a feature"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Create Segment override
&lt;/h3&gt;

&lt;p&gt;Let’s edit this feature and create a Segment override. A segment override essentially allows you to configure the feature flag behaviour based on traits of the user. We will use the trait as “profession” in our example.&lt;/p&gt;

&lt;p&gt;Click on the feature and navigate to the “Segment Overrides” tab. Click on “Create Feature-Specific Segment”&lt;/p&gt;

&lt;p&gt;Adding an override for users with &lt;code&gt;profession = freelancer&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Febi7bxkb82xb5yi3ucua.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Febi7bxkb82xb5yi3ucua.png" alt="Creating a segment with Flagsmith"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Segments can also be created globally for the project but in this case we just wanted the segment override for this one feature.&lt;/p&gt;

&lt;p&gt;Segment overrides let you specify the enabled state and remote configuration of the feature. You can add as many segment overrides to a feature as you want, the priority of the overrides are dictated by their order.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fau5ol98zl0y4pi5rzcmt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fau5ol98zl0y4pi5rzcmt.png" alt="Creating a segment override"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that the segment override is added, Turn it on and save the override. Note that by default the feature is turned off, and only for this segment we have turned it on.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh4g5s11r5avcr11t3s17.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh4g5s11r5avcr11t3s17.png" alt="Turning the feature on for a segment override"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Control card with Flagsmith
&lt;/h3&gt;

&lt;p&gt;TL;DR - Refer to this Pull request for the code changes - &lt;a href="https://github.com/abhishekag03/vercel-flagsmith-integration/pull/3/files" rel="noopener noreferrer"&gt;https://github.com/abhishekag03/vercel-flagsmith-integration/pull/11&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add the below import to &lt;code&gt;app/about/page.tsx&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useFlags&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flagsmith/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Initialise the flag variable by telling it which feature flag key needs to be read&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// only causes re-render if specified flag values change&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;flags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useFlags&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;configure_card_controller&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; 


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now, wrap the newly added card (“Configure” card) inside a condition, which checks for this flag.&lt;/p&gt;

&lt;p&gt;The way we read the value of our flag is:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;configure_card_controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enabled&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To conditionally view the configure card, we will just enclose that card markup inside the following:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;configure_card_controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; 
        &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="c1"&gt;// the card segment code&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/a&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;)}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In order to get the appropriate screen when the user reaches this screen, we need to make sure that the flag trait gets set appropriately.&lt;/p&gt;

&lt;p&gt;We will modify the &lt;code&gt;handleOnSubmit&lt;/code&gt; function to set the trait.&lt;/p&gt;

&lt;p&gt;Add the below import and the line highlighted in green to the &lt;code&gt;handleOnSubmit&lt;/code&gt; function inside &lt;code&gt;app/page.tsx&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;The following code sets a Flagsmith &lt;code&gt;trait&lt;/code&gt; value based on user selection. Setting a trait is async, it will fetch the latest flags, considering any new segment overrides the user may have as a result of the trait.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;flagsmith&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flagsmith/isomorphic&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleOnSubmit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FormEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLFormElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;flagsmith&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setTrait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;profession&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// setting the "profession" trait as the one selected by user&lt;/span&gt;

 &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/about?name=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;position=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;   &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We need useRouter to get the information passed from the Login page.&lt;/p&gt;

&lt;p&gt;We need to specify what flags and traits we are going to use in the code. As shown above, we are using the “configure_card_controller” flag and “profession” trait. This makes the flags variable tightly coupled with these names, thereby reducing our chances of error while coding.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing and Experimentation
&lt;/h2&gt;

&lt;p&gt;Deploy this code to Vercel and start testing.&lt;/p&gt;

&lt;p&gt;Notice that when you choose the profession as Freelancer, you will see 5 cards. The “Configure” card should be present.&lt;/p&gt;

&lt;p&gt;On choosing any other profession, only 4 cards are visible:&lt;/p&gt;

&lt;p&gt;You might be thinking that this could have been achieved with a trivial if/else condition - why do we need Flagsmith?&lt;/p&gt;

&lt;p&gt;Flagsmith allows you to control these configurations on the fly without needing any code change or any redeployment.&lt;/p&gt;

&lt;p&gt;For instance, if we see a good response from this new card - we would want to extend it to another Profession. To do that, we just need to go to the flagsmith UI and add the new profession name.&lt;/p&gt;

&lt;p&gt;Let’s try that - update the segment to also allow the “designer”  profession to see this new card.&lt;/p&gt;

&lt;p&gt;Edit the segment and add a condition for profession = “designer”.&lt;/p&gt;

&lt;p&gt;On redeploying, you can see that both Freelancer and Designers are able to see this new card. The third profession (Frontend Developer) is still seeing the 4 cards.&lt;/p&gt;

&lt;p&gt;Let’s push this code and get it deployed to our main site.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc6110cw8k1na4me7p8a5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc6110cw8k1na4me7p8a5.png" alt="Viewing our feature flag in Vercel"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The code is now live, and we are free to update the user segment and rollout as we need. You can test it running on &lt;a href="https://vercel-flagsmith-integration.vercel.app/" rel="noopener noreferrer"&gt;https://vercel-flagsmith-integration.vercel.app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Without any pull requests, code change, redeployment or testing, we were able to alter the behaviour of our website. This is a very powerful integration and can be used extensively for all small to large scale projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In conclusion, through this article, we demonstrated the practical application and significance of feature flags in a Next.js project hosted on Vercel. By integrating Flagsmith, we showcased how Next.js feature flags empower developers to reduce deployment risks, experiment safely, and deliver personalized user experiences. The ease of dynamic updates and segment overrides highlights the agility and control feature flags provide without code changes or redeployment. Through this hands-on approach, you can fine-tune feature rollouts and adapt your application based on user feedback, making feature flags a valuable tool for iterative and user-centric development. Embrace feature flags to unlock new possibilities and deliver exceptional user experiences in your software projects.&lt;/p&gt;

&lt;p&gt;Hope you found this article useful and this integration helps you in building out applications!&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Improving your React Native application performance with react-navigation-focus-render</title>
      <dc:creator>Kyle Johnson</dc:creator>
      <pubDate>Sun, 20 Feb 2022 15:25:46 +0000</pubDate>
      <link>https://dev.to/kylessg/improving-your-react-native-application-performance-with-react-navigation-focus-render-2hih</link>
      <guid>https://dev.to/kylessg/improving-your-react-native-application-performance-with-react-navigation-focus-render-2hih</guid>
      <description>&lt;p&gt;Performance in React Native has always been a bit of a battle, great performance is achievable but is a lot more sensitive to unoptimized code than traditional web development.&lt;/p&gt;

&lt;h1&gt;
  
  
  Background
&lt;/h1&gt;

&lt;p&gt;I'd recently discovered an issue in my application where my home tab screen had a collection of components that contained multiple re-renders. &lt;/p&gt;

&lt;p&gt;The problem was quite straightforward to resolve, but during this, I found out that this non-performant screen was slowing down the other tabs within my application.&lt;/p&gt;

&lt;h1&gt;
  
  
  A simple example of why this happened
&lt;/h1&gt;

&lt;p&gt;Let's make a simple example that replicates this issue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ExpensiveComponent&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here's our component that's causing the issue, every time this renders we'll see an obvious performance hit. It's connected to redux and will re-render whenever the state changes for the count.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const ExpensiveComponent = () =&amp;gt; {
  const {count} = useSelector((state) =&amp;gt; ({
    count: state.count,
  }));
  return  (
    &amp;lt;&amp;gt;
      {!!count &amp;amp;&amp;amp; &amp;lt;Text&amp;gt;Count is {count}&amp;lt;/Text&amp;gt;}
      {new Array(5000).fill(0).map((v, k) =&amp;gt; (
        &amp;lt;Text key={k}&amp;gt;{v}&amp;lt;/Text&amp;gt;
      ))}
    &amp;lt;/&amp;gt;
  );
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;HomeScreen&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Our home screen renders the expensive component and lets us go to screen 2. As long as ExpensiveComponent is re-rendering we will see an obvious performance hit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const HomeScreen = () =&amp;gt; {
    const navigation = useNavigation();
    const goScreen2 = ()=&amp;gt;{
        navigation.navigate('Screen2')
    }
    return (
        &amp;lt;&amp;gt;
            &amp;lt;Button
                title={'Go to Screen 2'}
                onPress={goScreen2}
            /&amp;gt;
            &amp;lt;ExpensiveComponent /&amp;gt;
        &amp;lt;/&amp;gt;
    );
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Screen2&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Our second screen has no performance issues by itself, it contains a button that dispatches an action to update the count. It doesn't render much and you'd expect pressing the button and displaying an updated count to be immediate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Screen2: React.FC&amp;lt;ComponentType&amp;gt; = ({}) =&amp;gt; {
    const {count} = useSelector((state) =&amp;gt; ({
        count: state.count,
    }));
    const dispatch = useDispatch();
    const setCount = useCallback(
        (data: number) =&amp;gt; {
            return dispatch(AppActions.setCount(data));
        },
        [dispatch],
    );
    const onPress = ()=&amp;gt; {
        setCount((count || 0) + 1)
    }
  return (
      &amp;lt;Button
        onPress={onPress}
        title={`Update Count (${count || 0})`}/&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You would expect Screen2 to have no performance issues right? Wrong. Pressing the update count button was consistently blocking the UI by around 250ms, this can be seen by using a tool I made, &lt;a href="https://github.com/Flagsmith/react-native-performance-monitor" rel="noopener noreferrer"&gt;react-native-performance-monitor&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftymk379b2g5oed0d42c2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftymk379b2g5oed0d42c2.png" alt="React Native Performance Monitor" width="800" height="646"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  So why did this happen?
&lt;/h1&gt;

&lt;p&gt;The reason made sense, other tabs were using updating the state that was also used on the HomeTab and as it turned out, inactive tabs will re-render even if they aren't shown.&lt;/p&gt;

&lt;p&gt;Even with optimized components, the fact that this happens is useful to be aware of. If you have 5 tabs in your app that have been visited in a session, any state updates can trigger re-renders on all of them.&lt;/p&gt;

&lt;h1&gt;
  
  
  Preventing this behavior with &lt;a href="https://github.com/Flagsmith/react-navigation-focus-render" rel="noopener noreferrer"&gt;react-navigation-focus-render&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;This is where my new npm package comes in. By wrapping the render our ExpensiveComponent in &amp;lt;FocusRender, children are not re-rendered until the screen is focused&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const ExpensiveComponent = () =&amp;gt; {
  const {count} = useSelector((state) =&amp;gt; ({
    count: state.count,
  }));
  return  (
    **&amp;lt;FocusRender&amp;gt;**
      {!!count &amp;amp;&amp;amp; &amp;lt;Text&amp;gt;Count is {count}&amp;lt;/Text&amp;gt;}
      {new Array(5000).fill(0).map((v, k) =&amp;gt; (
        &amp;lt;Text key={k}&amp;gt;{v}&amp;lt;/Text&amp;gt;
      ))}
    **&amp;lt;/FocusRender&amp;gt;**
  );
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simply by adding this, our example is more performant. Here's the comparison to prove it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faxy5i8s1ny7b1didn0sm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faxy5i8s1ny7b1didn0sm.png" alt="Focus Render" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This shows an average render time of around 6ms vs the original 250ms.&lt;/p&gt;

&lt;h1&gt;
  
  
  How does this work?
&lt;/h1&gt;

&lt;p&gt;It's quite simple, This module works by preventing screen re-renders of inactive screens until that screen is focused.&lt;/p&gt;

&lt;p&gt;The entire code can be found &lt;a href="https://github.com/Flagsmith/react-navigation-focus-render/blob/main/lib/index.js" rel="noopener noreferrer"&gt;here&lt;/a&gt;. It uses the useIsFocused() hook provided by react-navigation combined with a classic shouldComponentUpdate, returning true only if the screen is focused.&lt;/p&gt;

&lt;p&gt;To illustrate this clearly, here's how the above example behaves.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frecordit.co%2Fr6UiKKtlQ6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frecordit.co%2Fr6UiKKtlQ6.gif" alt="Example" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, it's noticeable when this re-render occurs due to how expensive the component is. However, in cases less extreme, it's more likely to behave like the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frecordit.co%2FXSq5RbuoQ1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frecordit.co%2FXSq5RbuoQ1.gif" alt="Example2" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Although this library should not replace optimizing components,  I believe with big applications this library can introduce big performance benefits. &lt;/p&gt;

&lt;p&gt;Let me know if you find this useful, you can check it out on &lt;a href="https://github.com/Flagsmith/react-navigation-focus-render" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; :) &lt;/p&gt;

&lt;p&gt;Happy Hacking!&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>react</category>
      <category>showdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Using Feature Flags to troll our competitor without a line of code 😃</title>
      <dc:creator>Kyle Johnson</dc:creator>
      <pubDate>Mon, 14 Feb 2022 20:40:26 +0000</pubDate>
      <link>https://dev.to/kylessg/we-trolled-our-competitor-without-pushing-a-single-line-of-code-43jf</link>
      <guid>https://dev.to/kylessg/we-trolled-our-competitor-without-pushing-a-single-line-of-code-43jf</guid>
      <description>&lt;h1&gt;
  
  
  The back story
&lt;/h1&gt;

&lt;p&gt;📖 When we built &lt;a href="https://flagsmith.com" rel="noopener noreferrer"&gt;Flagsmith&lt;/a&gt;, we decided early on to power the admin dashboard with our own Feature Flags. As well as following a methodology we truly believed in, this meant we could be super flexible in how our admin panel behaves.&lt;/p&gt;

&lt;p&gt;This proved very useful in the story I'm about to share.&lt;/p&gt;

&lt;h1&gt;
  
  
  How it began
&lt;/h1&gt;

&lt;p&gt;🕒 It's Monday 6 pm and I'm just about to wrap up for the day. &lt;/p&gt;

&lt;p&gt;Early on during product development, we wrote a crude SlackBot that alerted us to signups from new email domains we haven't seen before. At 6:38 pm UK Time, we saw a new domain, it was our biggest feature flag competitor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F76u49lfzqakoergyp2hg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F76u49lfzqakoergyp2hg.png" alt="Flagsmith Slack"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Laying the foundations
&lt;/h1&gt;

&lt;p&gt;The first step was to make sure this prank wasn't going to affect anyone else, I may have been caffeine depleted but I wasn't going to go full-on cowboy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7g5j2so2gs8klh29f1su.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7g5j2so2gs8klh29f1su.png" alt="Feature Flag Segments"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;💡 I created a segment to match any user from the company's domain, users are given a trait of their email address when they log in so I was easily able to target that trait with a regular expression. &lt;/p&gt;

&lt;p&gt;😇 In the interest of privacy I've hidden said domain from the post. If someone from there is reading this, you're welcome. &lt;/p&gt;

&lt;p&gt;🕵️‍♂️ I also added in my email so I could see what they see, think of it as testing in production.&lt;/p&gt;

&lt;p&gt;🤔 At this point I had quite a few options.&lt;/p&gt;

&lt;h1&gt;
  
  
  A simple butter bar
&lt;/h1&gt;

&lt;p&gt;I felt like off starting off lightly, just a simple hello to let them know we know.&lt;/p&gt;

&lt;p&gt;Thankfully this was really easy, we have a butter bar messaging feature to send out suitable messaging to segments of users. &lt;/p&gt;

&lt;p&gt;😃 Our cheeky user segment should definitely get a personalised message.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd4s0rmd4pbp2bo4ptrhc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd4s0rmd4pbp2bo4ptrhc.png" alt="Feature targeting"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That was easy, now they see a lovely message on every page they take a look at!&lt;/p&gt;

&lt;h1&gt;
  
  
  A more bespoke experience
&lt;/h1&gt;

&lt;p&gt;This was nice but I felt like I could do more for them.&lt;/p&gt;

&lt;p&gt;⭐ I decided they deserved their very own SDK integration on our platform. I'm sure this is something they'd enjoy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4npf49q5li1kf5k6h7xx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4npf49q5li1kf5k6h7xx.png" alt="Remote config is great"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  The result
&lt;/h1&gt;

&lt;p&gt;This bit of remote config leads to a much more personalised user experience for our new users.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqnq5szi5qtpgc2m93uh5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqnq5szi5qtpgc2m93uh5.png" alt="Perfect"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👌 In the end there can only be one feature flag platform.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frecordit.co%2F3UzDNP00pb.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frecordit.co%2F3UzDNP00pb.gif" alt="Flagsmith"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>showdev</category>
    </item>
    <item>
      <title>What I've learned creating a React / React Native performance monitor</title>
      <dc:creator>Kyle Johnson</dc:creator>
      <pubDate>Fri, 20 Mar 2020 18:01:44 +0000</pubDate>
      <link>https://dev.to/kylessg/what-i-ve-learned-creating-a-react-native-performance-monitor-k98</link>
      <guid>https://dev.to/kylessg/what-i-ve-learned-creating-a-react-native-performance-monitor-k98</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dcUjHLw1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://github.com/BulletTrainHQ/react-native-performance-monitor/raw/master/example.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dcUjHLw1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://github.com/BulletTrainHQ/react-native-performance-monitor/raw/master/example.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This post covers an introduction to react-native-performance monitor, a realtime performance monitor for React Native I've just made (which would also work for React). The tool is completely open-source, &lt;a href="https://www.npmjs.com/package/react-native-performance-monitor"&gt;published on npm&lt;/a&gt; and can be &lt;a href="https://github.com/BulletTrainHQ/react-native-performance-monitor#readme"&gt;checked out here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://bullet-train.io/blog/react-native-performance-monitor"&gt;(original post here)&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;Even for the most experienced React Native developer, maintaining and improving performance in a large React Native app can be far from trivial. Also, the act of implementing performance improvements is an art in itself. Based on experience here's my checklist for a starting such an approach:&lt;/p&gt;

&lt;h3&gt;
  
  
  1 - Don't jump straight in, get a benchmark!
&lt;/h3&gt;

&lt;p&gt;This is probably the most important point, and above all, is the main motivator for this tool. &lt;/p&gt;

&lt;p&gt;Although it's very tempting to jump in and chop away at ugly lines of code, without a real measurement of a before and after a lot of the times you're pretty much none the wiser how big of an impact you made (the odd change here and there may even introduce a performance deficit) &lt;/p&gt;

&lt;h3&gt;
  
  
  2 - Make sure there's a good cost-benefit
&lt;/h3&gt;

&lt;p&gt;Simply put, if you've reduced the maintainability and readability of the code for a couple of milliseconds improvement, it's probably not worth it. To reiterate the first point, this is made a lot easier if you have numbers to back this up, don't introduce bias and the phrase "it feels faster".  &lt;/p&gt;

&lt;h3&gt;
  
  
  3 - Record your findings
&lt;/h3&gt;

&lt;p&gt;You've reached a mind-melting conclusion that will improve your React Native knowledge forever, great! Record your finding and document them / share it with your team.&lt;/p&gt;

&lt;h3&gt;
  
  
  4 - Periodically retest
&lt;/h3&gt;

&lt;p&gt;Without a good way to test performance again at a later date, you could find that your hard work is ruined by regression.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Profiler in React Native
&lt;/h2&gt;

&lt;p&gt;As of &lt;a href="https://github.com/react-native-community/releases/blob/master/CHANGELOG.md#0610"&gt;React Native 0.61.0&lt;/a&gt;, the React Profiler is now officially stable. &lt;a href="https://reactjs.org/docs/profiler.html"&gt;Profiler&lt;/a&gt; component exposes the following callback as a prop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function onRenderCallback(
  id, // the "id" prop of the Profiler tree that has just committed
  phase, // either "mount" (if the tree just mounted) or "update" (if it re-rendered)
  actualDuration, // time spent rendering the committed update
  baseDuration, // estimated time to render the entire subtree without memoization
  startTime, // when React began rendering this update
  commitTime, // when React committed this update
  interactions // the Set of interactions belonging to this update
)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This release allows you to also profile interactions much like you'd do in chrome on the web.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jfRxFxBf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://reactjs.org/static/3046f500b9bfc052bde8b7b3b3cfc243/1e088/flame-chart.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jfRxFxBf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://reactjs.org/static/3046f500b9bfc052bde8b7b3b3cfc243/1e088/flame-chart.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although useful, I have a few problems with using this to test performance and iterate.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The feedback loop is slow. This requires a process of recording, writing down the numbers, making a change and then recording again.&lt;/li&gt;
&lt;li&gt;The information can kind of become a bit overwhelming and confusing to work with, this is especially true with larger applications with many nested components.&lt;/li&gt;
&lt;li&gt;The output of the tests depends on how quickly you hit record and performed the interactions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I get the best use out of this by using it to figure out a starting place of what to work on. But in my mind, I feel like making performance improvements needs a different tool, one that provides immediate, a/b comparison based feedback.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing react-native-performance-monitor
&lt;/h2&gt;

&lt;p&gt;Considering the above I decided to get to work in making this tool. I've been using it for a few weeks and believe the best approach is to:&lt;/p&gt;

&lt;p&gt;1 - Identify an area of the application you feel needs improving (maybe via the React Profiler).&lt;br&gt;
2 - Record your baseline by either triggering a component mount or force update, I added x5 and x10 buttons to get a better average baseline. Whether you choose to test remounting or force updates depends on the nature of what you are trying to test, if your component receives frequent updates somewhere in the tree you may see a lot of benefits just concentrating solely on updates.&lt;br&gt;
3 - Whilst you are developing pause the recorder, then when you want to out your changes add a variant and click resume.&lt;br&gt;
4 - Repeat 3 as many times as you need to to reach an improvement, to reduce the noise you can always clear tests that you wish to discard. &lt;/p&gt;

&lt;p&gt;I thought I knew React Native inside and out having worked on it since 2015, but seeing metrics for every little change opens up a rabbit hole of things you thought you knew. It's strangely addicting to play around with. &lt;/p&gt;

&lt;p&gt;The amount of subtle changes with components and their impact has surprised me, for example: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--G823Vahp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/BulletTrainHQ/react-native-performance-monitor/raw/master/example2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--G823Vahp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/BulletTrainHQ/react-native-performance-monitor/raw/master/example2.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This difference was entirely down to the following code. I, of course, could understand why this would be the case however I'd not predicted the effect this change would have. &lt;/p&gt;

&lt;p&gt;Before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Text style={[this.props.style]}&amp;gt;
    {this.props.children}
&amp;lt;/Text&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Text style={this.props.style}&amp;gt;
    {this.props.children}
&amp;lt;/Text&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;The overall implementation is quite straight forward and simply involved passing the onRenderCallback values via a WebSocket server to finally render them in a fancy graph.&lt;/p&gt;

&lt;p&gt;There are 3 main components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;a href="https://github.com/BulletTrainHQ/react-native-performance-monitor/blob/master/lib/provider.js"&gt;React Native component&lt;/a&gt; that sends profile data to a server via REST and listens to messages (remount and force update) to trigger renders.&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://github.com/BulletTrainHQ/react-native-performance-monitor/blob/master/lib/src/server.js"&gt;Web socket server&lt;/a&gt; responsible for passing messages between the graph and the react-native component&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://github.com/BulletTrainHQ/react-native-performance-monitor/blob/master/components/App.js"&gt;Web application&lt;/a&gt; that receives WebSocket values and renders them to a graph&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The following diagram is a brief explanation of the data flow:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PUAR9pB1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/BulletTrainHQ/react-native-performance-monitor/raw/master/data-flow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PUAR9pB1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/BulletTrainHQ/react-native-performance-monitor/raw/master/data-flow.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;Hopefully this has encouraged you to also jump into the rabbit hole of optimising your app. This project is still in its infancy but I'm open for feedback and how it could further help everyone out. &lt;a href="https://github.com/BulletTrainHQ/react-native-performance-monitor"&gt;Check it out&lt;/a&gt; and let me know! &lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>react</category>
      <category>showdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Achieving a perfect 100% Google Lighthouse audit score with Next and Redux</title>
      <dc:creator>Kyle Johnson</dc:creator>
      <pubDate>Mon, 26 Aug 2019 11:10:17 +0000</pubDate>
      <link>https://dev.to/kylessg/achieving-a-perfect-100-google-lighthouse-audit-score-with-next-js-and-redux-5p0</link>
      <guid>https://dev.to/kylessg/achieving-a-perfect-100-google-lighthouse-audit-score-with-next-js-and-redux-5p0</guid>
      <description>&lt;p&gt;&lt;a href="https://camo.githubusercontent.com/60e01c505310b31551ee45c7f8a144bc4c69cfcb/687474703a2f2f672e7265636f726469742e636f2f545938776369547351482e676966" class="article-body-image-wrapper"&gt;&lt;img src="https://camo.githubusercontent.com/60e01c505310b31551ee45c7f8a144bc4c69cfcb/687474703a2f2f672e7265636f726469742e636f2f545938776369547351482e676966"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(Moved to &lt;a href="https://bullet-train.io/blog/100-percent-lighthouse-score" rel="noopener noreferrer"&gt;here&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;This post covers how we can build a React/NextJS app with Redux that achieves a 100% audit score with server-rendering, localisation support and can be installed as a PWA and navigated whilst offline.&lt;/p&gt;

&lt;h1&gt;
  
  
  next.js
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://nextjs.org" rel="noopener noreferrer"&gt;next.js&lt;/a&gt; is my new favourite thing. Built specifically for react, NextJS lets you server render your react application with little compromise to how you would normally build your app.&lt;/p&gt;

&lt;p&gt;Developing a React app will be pretty familiar, you'll have to switch out react-router with their built-in router, and be aware that your components will have to be executable in NodeJS (just like if you were unit testing them).&lt;/p&gt;

&lt;p&gt;The main difference is this bit of magic which we can add to our pages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Calls before the page is mounted, the call will happen on the server if it's the first page we visit
static async getInitialProps({ ctx: { store } }) {
  await store.dispatch(AppActions.getWidgets());
  return {};
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any asynchronous tasks or fetching can occur here on our pages.&lt;/p&gt;

&lt;p&gt;Rather than regurgitate all of the power of next, I'd recommend just stepping through their &lt;a href="https://nextjs.org/learn/basics/getting-started" rel="noopener noreferrer"&gt;getting started guide&lt;/a&gt;. This post details how I added redux, sagas and achieved a 100% score on Lighthouse.&lt;/p&gt;

&lt;h1&gt;
  
  
  I'm bored, just send me the code.
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://github.com/kyle-ssg/nextjs-redux" rel="noopener noreferrer"&gt;Fine&lt;/a&gt;. The project is also hosted at &lt;a href="https://nextjs-redux.kyle-ssg.now.sh/" rel="noopener noreferrer"&gt;https://nextjs-redux.kyle-ssg.now.sh/&lt;/a&gt;. But read on if you're interested.&lt;/p&gt;

&lt;h1&gt;
  
  
  1. next.js with Redux
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FpZsxSRF%2Fimage.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FpZsxSRF%2Fimage.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Rather than defining routes within JavaScript, routes in next are based on what's in your /pages directory.&lt;br&gt;
Next.js defines how pages are rendered with an App component, which we can customise by making our very own _app.js. Great, that means we can create our store and give it our root app component just like any other app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import App, { Container } from 'next/app';
import Head from 'next/head';
import React from 'react';
import { Provider } from 'react-redux';
import createStore from '../common/store';
import withRedux from 'next-redux-wrapper';
class MyApp extends App {
    static async getInitialProps({ Component, ctx }) {
        let pageProps;
        // Ensure getInitialProps gets called on our child pages
        if (Component.getInitialProps) {
            pageProps = await Component.getInitialProps({ ctx });
        }

        return { pageProps };
    }

    render() {
        const { Component, pageProps, store } = this.props;
        return (
            &amp;lt;Container&amp;gt;
                &amp;lt;Provider store={store}&amp;gt;
                    &amp;lt;&amp;gt;
                        &amp;lt;Head&amp;gt;
                            {/*...script and meta tags*/}
                            &amp;lt;title&amp;gt;TheProject&amp;lt;/title&amp;gt;
                        &amp;lt;/Head&amp;gt;
                        &amp;lt;Header/&amp;gt;
                        &amp;lt;Component {...pageProps} /&amp;gt;
                    &amp;lt;/&amp;gt;
                &amp;lt;/Provider&amp;gt;
            &amp;lt;/Container&amp;gt;
        );
    }
}

export default withRedux(createStore)(MyApp);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some of this will probably look familiar to you, the main differences being:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In our route app, we need to make sure our pages getInitialProps functions are being called before rendering&lt;/li&gt;
&lt;li&gt;Next.js provides a Head component that lets us render out any standard tags that live inside the head, this can even be done per page. This is useful for adding opengraph/meta tags/titles per page.&lt;/li&gt;
&lt;li&gt;next-redux-wrapper is an out of box library that lets us use createStore.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The outcome&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Adding a simple get widgets action we can see the following differences depending on if we loaded the page from landing straight on it vs navigating to it from another page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2F30xjFxy%2Fimage.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2F30xjFxy%2Fimage.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This happens because getInitialProps is called on the server during the initial page load, it knows which page to call it on based on the route.&lt;/p&gt;

&lt;h1&gt;
  
  
  2. Achieving a 100% Lighthouse score
&lt;/h1&gt;

&lt;p&gt;Even locally, I noticed how fast everything felt. This leads me to wonder how performant I could get the page. Within chrome dev tools there's a great tool called L that rates your site based on several recognised best practices and meets the progressive web app standard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Baseline score
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2F10VMz8W%2Fimage.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2F10VMz8W%2Fimage.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The baseline score was not too bad, with performance not being a problem for a redux page hitting an API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accessibility
&lt;/h2&gt;

&lt;p&gt;Most of these items are trivial to solve and involve employing best practices such as image alt tags, input roles and aria attributes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Appropriate colour contrast
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FY3FQhFk%2Fimage.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FY3FQhFk%2Fimage.png"&gt;&lt;/a&gt;&lt;br&gt;
Lighthouse is clever enough to know which of your elements are not meeting the WCAG 2 AA contrast ratio thresholds, stating that your foreground and background should have a contrast ratio of at least 4.5:1 for small text or 3:1 for large text. You can run tools such as &lt;a href="https://webaim.org/resources/contrastchecker/" rel="noopener noreferrer"&gt;Web AIM's contrast checker&lt;/a&gt;. A quick CSS change fixed this but obviously, this will mean a good amount of refactoring for content-rich sites.&lt;/p&gt;
&lt;h3&gt;
  
  
  Localisation
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FwpFPGtb%2Fimage.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FwpFPGtb%2Fimage.png"&gt;&lt;/a&gt;&lt;br&gt;
This one was a little more tricky. To do a good job of this I wanted the serverside render to detect the user's preferred locale and set the lang attribute as well as serve localised content. Searching around I did come across &lt;a href="https://github.com/isaachinman/next-i18next" rel="noopener noreferrer"&gt;next-i18next&lt;/a&gt;, however, I noticed that it doesn't support serverless and it's difficult to share locale strings with &lt;a href="https://www.npmjs.com/package/react-native-localization" rel="noopener noreferrer"&gt;react-native-localization&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I wanted something that would work with  &lt;a href="https://www.npmjs.com/package/react-localization" rel="noopener noreferrer"&gt;react-localization&lt;/a&gt;, so my approach was as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1: When the document attempts to render on the server, we want to get the preferred locale and set the lang attribute to the HTML tag. This info comes from the server, either from a cookie which we could set or by parsing the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language" rel="noopener noreferrer"&gt;Accept-Language Header&lt;/a&gt;. A code snippet for how I did this can be found &lt;a href="https://github.com/kyle-ssg/nextjs-redux/blob/master/project/api.js#L27" rel="noopener noreferrer"&gt;here&lt;/a&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    // _document.js
    static async getInitialProps(ctx) {
        const initialProps = await Document.getInitialProps(ctx);
        const locale = API.getStoredLocale(ctx.req);
        return { ...initialProps, locale };
    }
    ...
    render() {
        return (
            &amp;lt;html lang={this.props.locale}&amp;gt;
                ...
            &amp;lt;/html&amp;gt;
        )
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;2: I define some localised strings
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// localization.js
import LocalizedStrings from 'react-localization';

const Strings = new LocalizedStrings({
    en: {
        title: 'Hello EN',
    },
    'en-US': {
        title: 'Hello US',
    },
});

export default Strings;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;3: I want my app to know what the locale is in a store so that I can use that information later.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    // _app.js
    static async getInitialProps({ Component, ctx }) {
        let pageProps;
        const locale = API.getStoredLocale(ctx.req); // Retrieve the locale from cookie or headers
        await ctx.store.dispatch(AppActions.startup({ locale })); // Post startup action with token and locale
        ...
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;4: I set the language once in my app on the initial client &lt;strong&gt;and&lt;/strong&gt; server render.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// _app.js
render(){
        if (!initialRender) {
            initialRender = true;
            const locale = store.getState().locale;
            if (locale) {
                Strings.setLanguage(locale);
            }
        }
    ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;5: In my pages, I am now free to use localised strings.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    // pages/index.js
     render() {
            return (
                &amp;lt;div className="container"&amp;gt;
                    &amp;lt;h1&amp;gt;Home&amp;lt;/h1&amp;gt;
                    {Strings.title}
                &amp;lt;/div&amp;gt;
            );
      }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Best practices
&lt;/h3&gt;

&lt;p&gt;Since the project had pretty up to date libraries and didn't do anything unruly, this already had a good score. The only thing we had to do was use http2 and SSL, which is more down to how you're hosting the application. Using &lt;a href="https://zeit.co/" rel="noopener noreferrer"&gt;Zeit&lt;/a&gt; covered both of these.&lt;/p&gt;
&lt;h3&gt;
  
  
  SEO
&lt;/h3&gt;

&lt;p&gt;Thanks to nextJS you can easily add meta tags on a per-page basis, even using dynamic data from getInitialProps.&lt;/p&gt;
&lt;h3&gt;
  
  
  Progressive web app
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FWkBg4yK%2Fimage.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FWkBg4yK%2Fimage.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PWAs make our web apps installable, combined with service workers we can serve content whilst the user is offline.&lt;/p&gt;

&lt;p&gt;The first step was to add a simple manifest, this lets us configure how it should behave when installed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/static/manifest.json
{
  "short_name": "Project Name",
  "name": "Project Name",
  "icons": [
    {
      "src": "/static/images/icons-192.png",
      "type": "image/png",
      "sizes": "192x192"
    },
    {
      "src": "/static/images/icons-512.png",
      "type": "image/png",
      "sizes": "512x512"
    }
  ],
  "start_url": "/?source=pwa",
  "background_color": "#3367D6",
  "display": "standalone",
  "scope": "/",
  "theme_color": "#3367D6"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//_app.js
&amp;lt;link rel="manifest" href="/static/manifest.json"/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;Offline support with service workers&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Thanks to &lt;a href="https://github.com/hanford/next-offline#readme" rel="noopener noreferrer"&gt;next-offline&lt;/a&gt;, adding service worker support was simple. Getting the service worker to work with serverless and hosted on Zeit however was a bit fiddly, we had to add a route for our server to serve the correct content header.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// now.json
{
  "version": 2,
  "routes": [
    {
      "src": "^/service-worker.js$",
      "dest": "/_next/static/service-worker.js",
      "headers": {
        "Service-Worker-Allowed": "/"
      }
    }
    ...
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then configure next-offline to serve the service worker from static.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;next.config.js
{
    target: 'serverless',
    // next-offline options
    workboxOpts: {
        swDest: 'static/service-worker.js',
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  The result
&lt;/h1&gt;

&lt;p&gt;As a result of this, we now have a solid base project with a 100% audit score, server-rendered, localised and can be installed and navigated whilst offline. Feel free to &lt;a href="https://github.com/kyle-ssg/nextjs-redux" rel="noopener noreferrer"&gt;Clone it and hack around&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>showdev</category>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Our Tools - 2019 Edition</title>
      <dc:creator>Kyle Johnson</dc:creator>
      <pubDate>Mon, 24 Jun 2019 09:09:12 +0000</pubDate>
      <link>https://dev.to/kylessg/our-tools-2019-edition-533k</link>
      <guid>https://dev.to/kylessg/our-tools-2019-edition-533k</guid>
      <description>&lt;p&gt;Here's what we are using to build &lt;a href="https://bullet-train.io"&gt;Bullet Train, our Feature Flag platform&lt;/a&gt;. With some careful VPS purchases, most of this stuff can be run completely free of charge! &lt;/p&gt;

&lt;p&gt;(Moved to &lt;a href="https://bullet-train.io/blog/our-tools-2019"&gt;here&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  GitLab All The Things
&lt;/h2&gt;

&lt;p&gt;GitLab is pretty awesome, and it gets more awesome with every release. The big thing it has going for it is that it integrates a bunch of different tools, and makes them work together to help drive productivity. This also means that a single GitLab instance can manage a large part of the development process.&lt;/p&gt;

&lt;p&gt;We self-host GitLab. It is a fairly big application so we're running on a 3GB VM on Google's Cloud Platform, but you could easily use a cheaper VPS provider if you wanted to. The open source version of GitLab is called their "Community Edition", but don't be fooled, it's fully featured and is only missing a couple of items from their paid product. It installs pretty easily via their &lt;a href="https://about.gitlab.com/install/#ubuntu"&gt;Omnibus packages&lt;/a&gt;, and updating is pretty much just&lt;br&gt;
&lt;br&gt;
 &lt;code&gt;apt-get update; apt-get upgrade&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;You can also use their hosted product as we do, it has a great free tier.&lt;/p&gt;

&lt;h3&gt;
  
  
  Source Code
&lt;/h3&gt;

&lt;p&gt;Well, yeah obviously. All our code is pushed to GitLab. Being open source and self-hosted there are no limits to the number of developers or private projects you can host.&lt;/p&gt;

&lt;h3&gt;
  
  
  CI/CD
&lt;/h3&gt;

&lt;p&gt;GitLab has a first class CI/CD platform built in. You can get push-to-deploy working quickly and easily. There's only a couple of things you need to do to get up and running.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add a

&lt;code&gt;.gitlab-ci.yml&lt;/code&gt;

file to the root path of your project. This file contains the commands you need to build your product. 
2. Register a GitLab Runner, basically, a service that runs somewhere that can receive jobs from GitLab, run them, and send the results back to GitLab. You can even run the runner on the same machine as the GitLab Instance. &lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Agile Project Management
&lt;/h2&gt;

&lt;p&gt;We still think &lt;a href="https://trello.com/"&gt;Trello&lt;/a&gt; is the best of the bunch. It's fast, simple and gets out of the way. Having said that, they have recently been making some changes to their free tier, and so the one other option that might be worth checking out is, again, back in Gitlab. &lt;/p&gt;

&lt;p&gt;You can use the Gitlab issue tracker to manage requirements, and view them in a Kanban board, similar to Trello. A big advantage of doing this is, again, the tight integration between the Gitlab components. For example, if you push a commit with the message&lt;br&gt;
&lt;br&gt;
 &lt;code&gt;Fixes #252&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
, issue number 252 will be referenced by that commit. When you merge that commit into the master branch, Gitlab will even mark the issue as resolved! There's a bunch of other integrations that use this pattern. &lt;/p&gt;

&lt;h2&gt;
  
  
  Dev/Staging Builds
&lt;/h2&gt;

&lt;p&gt;We're using the amazing &lt;a href="http://dokku.viewdocs.io/dokku/"&gt;Dokku&lt;/a&gt; to run dev and feature branches. Dokku is an amazing bit of software that basically turns your VPS into a mini-Heroku platform. Its pretty simple to create and destroy feature branches, as well as build and deploy development builds. We use &lt;a href="https://github.com/IlyaSemenov/gitlab-ci-git-push"&gt;this Docker image&lt;/a&gt; to integrate Gitlab CI with Dokku. &lt;/p&gt;

&lt;h2&gt;
  
  
  Production Hosting
&lt;/h2&gt;

&lt;p&gt;This really depends on the application you are working on. For &lt;a href="https://bullet-train.io"&gt;Bullet Train, our Feature Flag platform&lt;/a&gt;, we actually split out the hosting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Our Web front-end is written in Node/JS and deployed to &lt;a href="https://cloud.google.com/appengine/docs/standard/"&gt;Standard AppEngine&lt;/a&gt;. It's mega-cheap (as in practically free) and rock solid. &lt;/li&gt;
&lt;li&gt;Our API is written in &lt;a href="https://www.django-rest-framework.org/"&gt;Django/DRF&lt;/a&gt; and uses a Postgres database as its data store. We host this on AWS and Elastic Beanstalk. This gives us decent automated scaling options and a simple deployment process. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Feature Flags
&lt;/h2&gt;

&lt;p&gt;Well, we definitely use our Feature Flags to help build our Feature Flags! To ensure a smooth CI/CD process, and to reduce the amount of code that is committed but not deployed, we use our &lt;a href="https://bullet-train.io"&gt;Bullet Train Feature Flags&lt;/a&gt; platform within Bullet Train itself. Meta. We have a decent free tier too, so we don't have to pay ourselves to run our feature flags. &lt;/p&gt;

&lt;h2&gt;
  
  
  Support, Email Etc
&lt;/h2&gt;

&lt;p&gt;All free! We're using FreshDesk for our customer issue tracker, &lt;a href="https://www.freshworks.com/statuspage/"&gt;FreshStatus&lt;/a&gt; for our status page and &lt;a href="https://uptimely.app/"&gt;Uptimely&lt;/a&gt; for our uptime monitoring/outage alerts. &lt;/p&gt;

&lt;p&gt;For email, we're using the pretty awesome &lt;a href="https://www.migadu.com"&gt;Migadu&lt;/a&gt; for inbound email, and SendGrid for our outbound email. &lt;/p&gt;

&lt;p&gt;For marketing, &lt;a href="https://www.mailerlite.com/"&gt;MailerLite&lt;/a&gt; to manage drip campaigns, and the free tier of &lt;a href="https://www.intercom.com/"&gt;Intercom&lt;/a&gt; to do our in-app chat. &lt;/p&gt;

</description>
      <category>productivity</category>
      <category>python</category>
      <category>javascript</category>
      <category>ci</category>
    </item>
    <item>
      <title>Overcoming bottlenecks between design, frontend and backend developers</title>
      <dc:creator>Kyle Johnson</dc:creator>
      <pubDate>Wed, 29 May 2019 19:13:10 +0000</pubDate>
      <link>https://dev.to/kylessg/overcoming-bottlenecks-between-design-frontend-and-backend-developers-2f1k</link>
      <guid>https://dev.to/kylessg/overcoming-bottlenecks-between-design-frontend-and-backend-developers-2f1k</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FQnSn2xD%2Ftraffic.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FQnSn2xD%2Ftraffic.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(Moved to &lt;a href="https://bullet-train.io/blog/overcoming-developer-bottlenecks" rel="noopener noreferrer"&gt;here&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;During my job as a frontend developer for Solid State Group, I've seen several scenarios which block work for specific areas of the development team. Be it design, markup/style implementation, technical frontend or backend, at one point or another they reach a point where they are relying on someone to complete some work before they can get on with their task.&lt;/p&gt;

&lt;p&gt;Over the past few years, I've been quite interested (rather selfishly) in finding as many ways as possible to get to a place all these people can work happily in parallel as much as possible without being ground down to a halt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some scenarios
&lt;/h2&gt;

&lt;p&gt;To set the scene, here are some examples of the sorts of things I'm referring to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A frontend developer wants to start building out a feature but the API isn't ready yet.&lt;/li&gt;
&lt;li&gt;A backend developer wants to start building out a feature but is not sure what frontend needs in terms of data.&lt;/li&gt;
&lt;li&gt;A backend developer is making some changes (e.g. removing some fields from a DTO) but is not sure if changes will break frontend.&lt;/li&gt;
&lt;li&gt;A technical frontend developer (who does not generally touch markup/CSS) is developing a feature but not sure what markup /styles are available to use.&lt;/li&gt;
&lt;li&gt;A design based frontend developer (who does purely markup/CSS) is ready to replicate designs but the technical frontend implementation or data isn’t ready.&lt;/li&gt;
&lt;li&gt;A designer adjusting markup but is unsure of how to get to the page required.&lt;/li&gt;
&lt;li&gt;A developer is validating a particular scenario issue or feature but has to go through tedious app state(onboarding etc) to get to the place they want.&lt;/li&gt;
&lt;li&gt;A developer new to a project needs onboarding from another developer to understand the codebase.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are some solutions...&lt;/p&gt;

&lt;h2&gt;
  
  
  Developing with pact-js
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fpact-foundation%2Fpact-logo%2Fmaster%2Fmedia%2Flogo-black.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fpact-foundation%2Fpact-logo%2Fmaster%2Fmedia%2Flogo-black.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
My recent experience with Pact is probably worth a post of its own, it has changed how we approach development on larger projects for the better and has saved an immense amount of time.&lt;/p&gt;

&lt;p&gt;Pact, by itself, is a contract testing tool. A consumer of data (in this case the frontend) defines what it wants from a data provider and publishes this to a broker before doing any work. Developers of the provider (in this case the API) reference this and use it to develop against.&lt;/p&gt;

&lt;p&gt;Both frontend and backend developers can work against this single source of truth once it is defined, using it as a basis to discuss changes if they arise. Expanding on Pact a bit, we've built on top of it to automatically generate a local mock server on the frontend.&lt;/p&gt;

&lt;p&gt;As a result, often we've found that we can develop a large chunk of an application only then to flip the switch from localhost to a development API to start integration testing. During this time both the frontend and backend developers aren't waiting for each other to complete bits of work before knowing where they stand.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before Pact&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We'd either have to wait for backend or frontend to be built first then wait for each other as we eventually deemed things weren't suitable.&lt;/li&gt;
&lt;li&gt;Optionally we could use something like Apiary. This albeit a great tool will not help you track changes and test that the current API is doing what the frontend needs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;After Pact!&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pact files are used as the single source of truth, tests can be written to ensure changes to the API payload won't affect the frontend.&lt;/li&gt;
&lt;li&gt;A frontend developer can use the Pact JSON as a mock server, this is really useful for developing when you can't reach the API or when endpoints don't exist/haven't been changed yet. This is much better than working against a static JSON variable because when the API is ready you can simply switch the endpoint from localhost.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Component based development and a style guide page
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fklecdce.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fklecdce.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Recently in our web and mobile projects, we've kept a page that contains every single component the application presents. In particular, I've found this works really well with React and React Native.&lt;/p&gt;

&lt;p&gt;Non-technical developers on the design side can implement the designs without getting bogged down in application logic, while technical developers have a reference to what markup to use when implementing new features.&lt;/p&gt;

&lt;p&gt;Not only this, but it often means that any bugs or tweaks to do with appearance can be worked on once in a single place rather than tracking down a certain screen or workflow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before style guide pages&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Technical developers would have to remember what CSS classes and components correspond to certain designs.&lt;/li&gt;
&lt;li&gt;Non-technical developers would get bogged down trying to find where to implement markup.&lt;/li&gt;
&lt;li&gt;To implement a change, developers would have to navigate the appropriate page, often including tedious workflow such as user registration/onboarding.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;After style guide pages!&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Technical developers can easily find and reuse components already developed by designers.&lt;/li&gt;
&lt;li&gt;Improves overall codebase by making developers develop simple, reusable components.&lt;/li&gt;
&lt;li&gt;Non-technical developers have a simple page that isn't bloated by code to implement the markup for their designs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Add teardown endpoints
&lt;/h2&gt;

&lt;p&gt;Being able to efficiently test workflows and clear down the data saves a lot of time and prevents the need from relying on backend developers to clear down databases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before teardown endpoints&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Development environments would get filled with garbage test data.&lt;/li&gt;
&lt;li&gt;Testers or developers may need to rely on data being cleared down before they can continue testing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;After teardown endpoints!&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Workflows can be tested over and over and cleared down without any repercussions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Develop your application so that you can simulate complicated scenarios
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fpracticaldev%2Fimage%2Ffetch%2Fs--Zt0VBETr--%2Fc_limit%252Cf_auto%252Cfl_progressive%252Cq_auto%252Cw_880%2Fhttps%3A%2F%2Fpreview.ibb.co%2FkkXXD9%2Fdownload.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fpracticaldev%2Fimage%2Ffetch%2Fs--Zt0VBETr--%2Fc_limit%252Cf_auto%252Cfl_progressive%252Cq_auto%252Cw_880%2Fhttps%3A%2F%2Fpreview.ibb.co%2FkkXXD9%2Fdownload.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Having covered this in a bit more detail in &lt;a href="https://dev.to/kylessg/using-feature-flags-for-client-demos-and-simulating-complex-scenarios-1gih"&gt;my post here&lt;/a&gt;, this idea is more about developers not being throttled by the complexity of a large app. &lt;/p&gt;

&lt;p&gt;I must have spent days on old projects constantly registering as a new user to test out onboarding or messing around with integrations with hardware just to get to the part I'm working on. &lt;/p&gt;

&lt;p&gt;The solution is to build your app in a way that it can be manipulated into certain states via a constants file, or better yet a &lt;a href="https://bullet-train.io" rel="noopener noreferrer"&gt;remotely configured feature flags&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before simulation flags&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Diagnosing and fixing bugs/features took a lot longer to replicate.&lt;/li&gt;
&lt;li&gt;Checking what happens in certain scenarios requires a lot of manual effort.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;After simulation flags&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Demonstration/replicability of scenarios takes a lot less time.&lt;/li&gt;
&lt;li&gt;Bugs and features in obscure parts of your application become a lot easier to develop on.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Standardising project structure and setup
&lt;/h2&gt;

&lt;p&gt;I won't go into how much developers should rely on boilerplate magic after all every project is different. In our case, we build 10s of projects per year, so having a standardised setup for development has been crucial.&lt;/p&gt;

&lt;p&gt;Previously, I'd seen developers sit together for half a day or more getting people set up and aware of the oddities of a particular project. Having a base layout project makes developers new on a project feel like they've worked on it before.&lt;/p&gt;

&lt;p&gt;If you are interested, here's a &lt;a href="https://dev.to/kylessg/a-sensible-approach-to-cross-platform-development-with-react-and-react-native-57pk"&gt;lite example&lt;/a&gt; of what our frontend project is based on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before Base layouts&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We'd have to invest a lot more time into initial project setup and infrastructure. &lt;/li&gt;
&lt;li&gt;Working on new projects was sometimes very painful to get going.&lt;/li&gt;
&lt;li&gt;New developers needed more support from the existing team for every project.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;After Base layouts!&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developers can start developing on a project a lot quicker and they are familiar with where to begin based on previous projects. &lt;/li&gt;
&lt;li&gt;Previous gotchas on projects are already covered based on previous iterations.&lt;/li&gt;
&lt;li&gt;Developers can more easily be switched in and out of projects without there being too much reliance on a select few.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hopefully, people have found some of these tips useful! Let me know what practices you use to help work better together.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>development</category>
      <category>productivity</category>
      <category>tips</category>
    </item>
    <item>
      <title>Step by Step - Writing end to end tests for your web project</title>
      <dc:creator>Kyle Johnson</dc:creator>
      <pubDate>Mon, 10 Dec 2018 23:25:04 +0000</pubDate>
      <link>https://dev.to/kylessg/step-by-step---writing-e2e-tests-for-your-web-project-4mde</link>
      <guid>https://dev.to/kylessg/step-by-step---writing-e2e-tests-for-your-web-project-4mde</guid>
      <description>&lt;p&gt;(Moved to &lt;a href="https://bullet-train.io/blog/writing-end-to-end-tests-web"&gt;Here&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Based on my previous post &lt;a href="https://dev.to/kylessg/hacking-our-e2e-tests-to-make-them-more-useful-2gaj"&gt;Hacking our e2e tests to make them more useful&lt;/a&gt;, there seemed to be little resources available for writing e2e tests. This is something I've become a strong advocate of since helping write &lt;a href="https://bullet-train.io"&gt;Bullet Train&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/1AIR5b2wYTtNUVuSlw/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/1AIR5b2wYTtNUVuSlw/giphy.gif" width="480" height="414"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This guide starts with a simple project and step by step adds e2e testing, each step links to a git diff so you can see exactly what I did. &lt;/p&gt;

&lt;p&gt;If you find this useful or would maybe prefer me to do a video covering this let me know.&lt;/p&gt;

&lt;h1&gt;
  
  
  The project
&lt;/h1&gt;

&lt;p&gt;End to end tests are super useful for regression testing time-consuming workflows, this example will go over perhaps the prime use-case for this, user registration and confirming a user's email address. &lt;/p&gt;

&lt;p&gt;The project is a simple react web application with a node backend, with it you can log in, register and receive a confirmation email address email using &lt;a href="https://sendgrid.com"&gt;SendGrid&lt;/a&gt;. Our test will go through all of this workflow so we don't have to keep manually testing it in the future. &lt;/p&gt;

&lt;p&gt;The scope of this tutorial isn’t to go over how the application is built, however as a brief overview:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There is a &lt;a href="https://github.com/kyle-ssg/e2e-tutorial/blob/master/server/api/user.js"&gt;Node API&lt;/a&gt; that has endpoints to log in, register and confirm email. &lt;/li&gt;
&lt;li&gt;Then on the frontend side we have &lt;a href="https://github.com/kyle-ssg/e2e-tutorial/tree/master/web/pages"&gt;a few pages&lt;/a&gt; written in React that host our login/register/confirm email address fields and functionality.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  1. Project Setup
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;The Project: &lt;a href="https://github.com/kyle-ssg/e2e-tutorial/tree/master"&gt;https://github.com/kyle-ssg/e2e-tutorial/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1.1. Installing nightwatch, selenium and chromedriver
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i nightwatch selenium-server chromedriver --save
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are going to need to install 3 things to get started:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Nightwatch - a nice API for interacting with web drivers and selenium.&lt;/li&gt;
&lt;li&gt;selenium-server - needed in order to run our web driver.&lt;/li&gt;
&lt;li&gt;chromedriver - communicates to the selenium server via WebDriver’s wire protocol. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Installing selenium-server and chrome driver as npm modules mean that you don't need to worry about global dependencies to run the tests. You can run this on any machine with different operating systems, and more importantly as part of CI pipelines without having to worry about if and where these binaries come preinstalled.&lt;/p&gt;

&lt;h2&gt;
  
  
  1.2. Writing a nightwatch.conf.js file
&lt;/h2&gt;

&lt;p&gt;Nightwatch comes with a lot of &lt;a href="http://nightwatchjs.org/gettingstarted#settings-file"&gt;configuration options&lt;/a&gt; which can be a bit overwhelming.&lt;/p&gt;

&lt;p&gt;Based on my experience here's the &lt;a href="https://github.com/kyle-ssg/e2e-tutorial/blob/master/nightwatch.conf.js"&gt;minimum config you'll need&lt;/a&gt;. The two key difference here to their default config is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We allow our chromedriver and selenium-server node modules to define where the binaries are located. &lt;/li&gt;
&lt;li&gt;We set end_session_on_fail to false, allowing us to interact with the browser if errors occur. &lt;a href="https://dev.to/kylessg/hacking-our-e2e-tests-to-make-them-more-useful-2gaj"&gt;More on how this can be useful here&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const chromedriver = require('chromedriver');
const seleniumServer = require('selenium-server');
const os = require('os');

const browserSize = 'window-size=1024,768'; // define how big to make the browser screen

module.exports = {

    'selenium': {
        'start_process': true, // tells nightwatch to start/stop the selenium process
        'server_path': seleniumServer.path,
        'cli_args': {
            'webdriver.chrome.driver': chromedriver.path, // chromedriver from our npm module
        },
    },

    'test_settings': {
        'end_session_on_fail': false, // don't close the browser straight away on fail in case we want to check the state
        'default': {
            'desiredCapabilities': {
                'browserName': 'chrome', // Run the e2e test in chrome
                'chromeOptions': {
                    // In linux we pass a few more arguments
                    'args': os.platform() === 'linux' ? ['headless', 'no-sandbox', browserSize] : [browserSize],
                },
            },
            'globals': {
                'waitForConditionTimeout': 5000, // global default time to wait for element to exist.
            },
        },
    },
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rather than go into a lengthy explanation, see the comments above on exactly what each property is used for.&lt;/p&gt;

&lt;h2&gt;
  
  
  1.3. adding a script in package.json to run tests
&lt;/h2&gt;

&lt;p&gt;In our package.json we just need to write an npm script to &lt;a href="https://github.com/kyle-ssg/e2e-tutorial/blob/master/package.json#L16"&gt;run nightwatch&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    "test:e2e": "nightwatch ./e2e/index.js"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  1.4. Writing our test entry file
&lt;/h2&gt;

&lt;p&gt;The entry file exports an object containing our tests and a before and after hook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = Object.assign(
    {
        before: (browser, done) =&amp;gt; { // Runs before tests start
            // runs before all of the tests run
            done();  // tell nightwatch we're done after we have done all of our bootstrapping
        },
        after: (browser, done) =&amp;gt; { // Runs after the tests have finished
            // runs after all of the tests run
            browser.end(); // kill the browser
            done(); // tell nightwatch we're done
        },
    },
    // the main tests
    require('./register.test')(),
    require('./login.test')(),
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  1.5. Our skeleton tests
&lt;/h2&gt;

&lt;p&gt;Before we go into writing our e2e tests, the following is some example syntax on how our tests are structured:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = () =&amp;gt; ({
    'Registration - test page loads': function (browser) {
        browser.url('https://google.com')
            .waitForElementVisible('body') // page load
    },
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We give each assertion a title, then we execute functions using the browser object. This may be&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Waiting for an element to be visible&lt;/li&gt;
&lt;li&gt;Clicking a button&lt;/li&gt;
&lt;li&gt;Setting the value of an input&lt;/li&gt;
&lt;li&gt;Switching to an iframe&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These functions are called one after another and wait for the previous to complete, they can be chained so that you can write whole workflows whilst keeping tests small e.g:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;browser.url('http://localhost:8080')
    .waitForElementVisible("#my-input")
    .setValue("#my-input", "test")
    .click("#my-button")
    .waitForElementVisible("#confirmation-button")
    .click("#confirmation-button");
    .waitForElementVisible(...)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, we are ready to start integrating Nightwatch with our code. We can currently run &lt;strong&gt;npm run test:e2e&lt;/strong&gt;* which launches Chrome, navigates to Google and validates that the body tag is visible. &lt;/p&gt;

&lt;h1&gt;
  
  
  2. Writing our first test
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://github.com/kyle-ssg/e2e-tutorial/compare/step_1_adding_our_first_test"&gt;Code for this section&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2.1 Running our application locally with Nightwatch
&lt;/h2&gt;

&lt;p&gt;So now that we have Nightwatch configured and we can run tests on external pages, we now want to do the same but on localhost as if we ran the application locally. The only tricky thing about this is that we need to know our server is ready before we progress with our tests. With a bit of trickery, we can do exactly that with Node's &lt;a href="https://nodejs.org/api/child_process.html#child_process_child_process_fork_modulepath_args_options"&gt;child_process.fork()&lt;/a&gt; which spawns a child process that can communicate via IPC.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
const fork = require('child_process').fork;

const server = fork('./server'); // start our server

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we start the server with &lt;strong&gt;&lt;em&gt;process.fork()&lt;/em&gt;&lt;/strong&gt; we listen for it to tell our parent process that it's done with &lt;strong&gt;&lt;em&gt;&lt;a href="https://github.com/kyle-ssg/e2e-tutorial/blob/master/server/middleware/webpack-middleware.js#L19"&gt;process.send({ done: true });&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;. Revisiting the before hook Nightwatch provides we wait for this acknowledgement message before starting the tests. Similarly, when the tests finish we want to kill the server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; before: (browser, done) =&amp;gt; {
            // runs before all of the tests run, call done() when you're finished
            server.on('message', () =&amp;gt; { // boot up the server which sends process.send({ done: true }); when ready
                done();
            });
        },
 after: (browser, done) =&amp;gt; {
            // runs before all of the tests run, call done() when you're finished
            browser.end(); // kill the browser
            done(); // tell nightwatch we're done
            server.kill('SIGINT'); // kill the server
        },        
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2.2 Targeting DOM elements sensibly
&lt;/h2&gt;

&lt;p&gt;While we could target our elements via their class name's or id's, I personally feel it's better to target via data-test properties. This way, you have a better idea of whether you're going to affect your tests. To add a bit of syntactic sugar I created the following util:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;byTestID: id =&amp;gt; `[data-test="${id}"]`,
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this setup, we add data-test="your_id" to the key elements and write our test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { byTestID } = require('./util');

module.exports = (email, password) =&amp;gt; ({
    'Registration - test page loads': function (browser) {
        browser.url('http://localhost:8080')
            .waitForElementVisible(byTestID('login-page')) // page load
            .click(byTestID('toggle-login')) // click toggle login
            .waitForElementVisible(byTestID('registration-email')) // wait for registration form
            .setValue(byTestID('registration-email'), email) // set fields
            .setValue(byTestID('registration-password'), password)
            .click(byTestID('registration-submit')) // submit form
            .waitForElementVisible(byTestID('check-email-page')); // wait for confirm email page
    },
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Finishing our confirm email tests with mailinator
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://github.com/kyle-ssg/e2e-tutorial/compare/step_1_adding_our_first_test...step_2_testing_confirm_email"&gt;Code for this section&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Most of the tests from here on are generally quite simple to write. The only tricky part was writing a few utility functions that deal with mailinator. This sort of thing you want to pull out from the main tests as you may want reuse to use/maintain them from one place.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; gotoMailinator(browser, email) {
        const target = email.replace('@mailinator.com', ''); // get the mailinator username
        // goto the inbox and wait for the content to be ready
        return browser.url(`https://www.mailinator.com/v3/index.jsp?zone=public&amp;amp;query=${target}#/#inboxpane`)
            .waitForElementVisible('#inboxpane');
    },
    clickFirstMailinatorMessage(browser) {
        // click the latest message in the inbox pane
        browser.waitForElementVisible('#inboxpane table tr td:nth-child(3n)')
            .click('#inboxpane table tr td:nth-child(3n)');
    },
    getMailinatorMessage(browser) {
        return browser.waitForElementVisible('#msg_body') // wait for the content to be ready
            .frame('msg_body') // switch to the message content's iframe
            .pause(1000); // the most reliable way I've found to ensure the content has loaded
    },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using this and writing some very similar tests to our first we end up with the above code and our end-to-end workflow of user registration, confirm email address and login.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/28evywxMTHbvLdLakP/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/28evywxMTHbvLdLakP/giphy.gif" width="478" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Expanding on this we would start writing tests that check that validation all checks out for invalid data and add test for any new major workflows.&lt;/p&gt;

&lt;p&gt;Feel free to checkout the example on GitHub, adding a .env file with SENDGRID_API_KEY="YOUR_KEY" should give you everything you need to run the tests!&lt;/p&gt;

&lt;p&gt;Happy hacking!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>testing</category>
      <category>e2e</category>
    </item>
    <item>
      <title>Hacking our e2e tests to make them more useful</title>
      <dc:creator>Kyle Johnson</dc:creator>
      <pubDate>Thu, 22 Nov 2018 16:24:01 +0000</pubDate>
      <link>https://dev.to/kylessg/hacking-our-e2e-tests-to-make-them-more-useful-2gaj</link>
      <guid>https://dev.to/kylessg/hacking-our-e2e-tests-to-make-them-more-useful-2gaj</guid>
      <description>&lt;p&gt;In this post, we're going to run through an overview of my experience using e2e tests for the &lt;a href="https://bullet-train.io/" rel="noopener noreferrer"&gt;feature flag platform, Bullet Train&lt;/a&gt;. I'll discuss the pros and cons of adding e2e coverage to your project, and how I eventually improved their usefulness with a bit of clever JavaScript. I'll also provide a code example that's used in production for all of you to play with.&lt;/p&gt;

&lt;h1&gt;
  
  
  What are end-to-end tests
&lt;/h1&gt;

&lt;p&gt;Unlike unit tests which verify individual segments of code are working, end-to-end (e2e) testing is a methodology that is more of a high-level run-through of your project, which tests whether automated interactions against the UI work as expected.&lt;/p&gt;

&lt;p&gt;In the case of a web project, we write code that launches a browser and tests the actual application as if we were a real user, interacting with elements and making sure the app behaves as e with both good and bad data.&lt;/p&gt;

&lt;p&gt;There are a bunch of frameworks that make this fairly easy to implement, in my case I've found that &lt;a href="http://nightwatchjs.org/" rel="noopener noreferrer"&gt;Nightwatch&lt;/a&gt; provides a very terse API and has been easy to work with. There are many alternatives in this area so it's mainly down to personal preference.&lt;/p&gt;

&lt;h2&gt;
  
  
  The benefits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Increases confidence in the application. We can write all the unit tests in the world, but there's no substitute for clicking around and verifying it all works together.&lt;/li&gt;
&lt;li&gt;Tests a lot of the component parts in one swoop with the least amount of effort. &lt;/li&gt;
&lt;li&gt;Great for regression. Actually running the application as our test touches everything: the UI, frontend business logic, contracts with API and even the API itself. If any of these things break it can be caught with E2E.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The drawbacks
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Can introduce annoying false positives. If the tests are written in a brittle fashion (e.g. looking for li&amp;gt;span&amp;gt;.myClass&amp;gt;input) it's easy to break them by changing the UI.&lt;/li&gt;
&lt;li&gt;If the UI of your project is constantly changing, the tests can be costly to maintain. Unit tests can often go untouched as they are isolated, however constant UI changes may require e2e tests to be maintained and regularly updated.&lt;/li&gt;
&lt;li&gt;Sometimes tests failure provide poor visibility of what the root cause of the error actually is.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This last point brings us to our topic at hand.&lt;/p&gt;

&lt;h1&gt;
  
  
  Better Root Cause Identification
&lt;/h1&gt;

&lt;p&gt;In the strive for achieving fault tolerance and redundancy, we recently we migrated the &lt;a href="https://bullet-train.io" rel="noopener noreferrer"&gt;Bullet Train API&lt;/a&gt; over to AWS. The move went pretty well, however we hit a brief issue where users were unable to create organisations. Straight away the E2E tests started shouting at us:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimage.ibb.co%2Fmg2OhA%2Fdownload.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimage.ibb.co%2Fmg2OhA%2Fdownload.png" width="800" height="214"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ok, great. But what does that actually mean? Thankfully, in this case, I had a pretty good hunch. We never reached the project selection page, due to us not being able to register. I clicked around on the site and figured out there was an API issue. This took a little while, but eventually, we fixed the API and our tests started to pass again. Although our tests caught the error, it took us quite a while to gather all the information we needed together to fix it. Clearly, the current level of error reporting wasn't good enough, so we set out to improve this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimage.ibb.co%2FniMG2A%2Fdownload-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimage.ibb.co%2FniMG2A%2Fdownload-1.png" width="670" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  1. Sending screenshots of e2e tests to slack
&lt;/h1&gt;

&lt;p&gt;This part was quite straightforward. Any selenium framework (even if it uses headless PhantomJS) has the ability to take screenshots of the browser in its current state. And fortunately Slack has a great API for uploading images to a channel.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
const Slack = require('node-slack-upload');
const slack = new Slack(process.env.SLACK_TOKEN); 
const uri = path.join(__dirname, 'screenshot.png');
...
        browser.saveScreenshot(uri, ()=&amp;gt; {
            slack.uploadFile({
                file: fs.createReadStream(uri),
                filetype: 'auto',
                title: "Screenshot",
                channels: Process.env.E2E_SLACK_CHANNEL},
            }, function (err, data) {
              ...
            });
        });

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is our basic starting point. Nightwatch provides a hook called &lt;strong&gt;after&lt;/strong&gt; that gets called after our test finishes (either by error or from finishing successfully). We just needed to make sure the browser doesn't close automatically when tests finish, so we can check what was left after the tests had run.&lt;/p&gt;

&lt;p&gt;Since we host this publicly on GitHub we make sure to always hide our sensitive tokens behind env variables!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
//nightwatch.conf:

"test_settings": {
        "default": {
            "end_session_on_fail": false,
            ...
        }
        ...
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
//index.test.js:
module.exports = Object.assign(
    require('./test1.js'),
    require('./test2.js'),
    {
        after: (browser, done) =&amp;gt; {
           uploadScreenshot(browser)
           ...

           server.kill('SIGINT');         
           browser.end();                 
           done();
       }
   }
)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And voila, we get our screenshot sent to slack when our test finishes!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimage.ibb.co%2FnNkZNA%2Fdownload-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimage.ibb.co%2FnNkZNA%2Fdownload-2.png" width="692" height="484"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  2. Reporting API errors
&lt;/h1&gt;

&lt;p&gt;This was where things get a bit clever. A common problem of end-to-end testing is the visibility of what's actually going on under the hood. After all, we're only really checking the state of DOM elements. Errors at the API or database level are a world away. &lt;/p&gt;

&lt;p&gt;So in order to report 'deeper' applications errors, our solution is to have our site write any relevant logging info to the DOM that we can then use later.&lt;/p&gt;

&lt;p&gt;We want to ensure this only happens when end-to-end tests are running, otherwise, we might accidentally leak out sensitive information to regular users.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Tell the frontend we are running E2E&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
//package.json:
    "test": "cross-env E2E=true nightwatch ./tests/index.test.js",

``

We set the environment variable E2E to true so we can tell WebPack to build the application in E2E mode.

``

plugins: [
    new webpack.DefinePlugin({
        E2E: !!process.env.E2E
    }),
...
]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Webpack's DefinePlugin allows us to set global variables for our site to access. In this case, window.E2E will now match our environment variable.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Writing debug information to the DOM&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 //Handle all requests
if (E2E) {
    const payload = {
        url,
        options,
    };
    document.getElementById('e2e-request').innerText = JSON.stringify(payload);
}

fetch(url, options)

...
//Handle all responses
(response, err) =&amp;gt; { // handling api errors
    req = fetch(url, options);
    if (E2E) {
        const error = {
            url: response.url,
            status: response.status,
            error: err,
        };
        document.getElementById('e2e-error').innerText = JSON.stringify(error);
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We then use this E2E variable to write our debug info to DOM elements. Which we send over to slack.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimage.ibb.co%2FmpWaCA%2Fdownload-3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimage.ibb.co%2FmpWaCA%2Fdownload-3.png" width="800" height="1268"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  A real-world example
&lt;/h1&gt;

&lt;p&gt;If you're curious to how this actually gets used in production, here's the commit which is now running in our gitlab pipelines &lt;a href="https://github.com/SolidStateGroup/bullet-train-frontend/commit/4a1d41b3ea103a3c2b823803d3fa273eae8bd49f" rel="noopener noreferrer"&gt;https://github.com/SolidStateGroup/bullet-train-frontend/commit/4a1d41b3ea103a3c2b823803d3fa273eae8bd49f&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Happy hacking!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>nightwatch</category>
      <category>e2e</category>
      <category>testing</category>
    </item>
    <item>
      <title>A sensible approach to Cross platform development with React and React Native</title>
      <dc:creator>Kyle Johnson</dc:creator>
      <pubDate>Mon, 27 Aug 2018 15:11:31 +0000</pubDate>
      <link>https://dev.to/kylessg/a-sensible-approach-to-cross-platform-development-with-react-and-react-native-57pk</link>
      <guid>https://dev.to/kylessg/a-sensible-approach-to-cross-platform-development-with-react-and-react-native-57pk</guid>
      <description>&lt;p&gt;The ability to develop simultaneously for Android, iOS and recently Windows Phone is often advertised as the biggest selling point for businesses considering adopting React Native. Arguably an even bigger and often overlooked opportunity this tech stack brings is the ability to extend this cross platform ecosystem to web with React. &lt;/p&gt;

&lt;p&gt;The end goal here is to be in a position where you can achieve and sustain feature parity with your web and mobile apps, written by a single team and have the ability to write new features and fix bugs simultaneously with a single codebase. &lt;/p&gt;

&lt;p&gt;This guide sets out an approach to building and maintaining a codebase that sensibly maximises shared functionality across all platforms. It concentrates solely on React/React Native so that you don't get bogged down with dependencies and state management systems like Redux and Mobx.&lt;/p&gt;

&lt;h1&gt;
  
  
  Project structure
&lt;/h1&gt;

&lt;p&gt;This may seem like an overly obvious place to start but it's important to set out a clear project structure with cross platform in mind so that you and your team know where everything lives.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;/common&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As the name states, any code that can be shared between web and mobile goes here. Whilst we want to maximise code sharing, it's important to be pragmatic and to not overfit code just to get a bit of reuse. Above all, our applications must be easy to understand and follow. By our rule of thumb, a module can be here if all the following requirements are met:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It does not depend on any modules which are not supported by web, mobile or node.&lt;/li&gt;
&lt;li&gt;It is platform agnostic and never contains code that checks which platform is executing it.&lt;/li&gt;
&lt;li&gt;It does not contain any markup anything presentational.&lt;/li&gt;
&lt;li&gt;Its functionality does not make assumptions that can hinder UX differences between web and mobile.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With these rules in mind, some examples of of common modules include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your application's API calls.&lt;/li&gt;
&lt;li&gt;State management (Redux, MobX etc).&lt;/li&gt;
&lt;li&gt;Environment config / constants.&lt;/li&gt;
&lt;li&gt;Common utility functions.&lt;/li&gt;
&lt;li&gt;Application business logic.&lt;/li&gt;
&lt;li&gt;Higher order components.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;/mobile&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the root of your React Native project, to keep things tidy we store our app structure under &lt;strong&gt;/mobile/app&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;/styles&lt;/strong&gt;: contains all your project styles with a single file to store our config / style variables such as colours and font sizes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;/components&lt;/strong&gt;: contains all your project components, generally these components mostly just care about presentation and are stateless.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;/pages&lt;/strong&gt;: keeping pages separate from the component folder makes them easier to find.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;/project&lt;/strong&gt;: contains any none-presentational but specific config to mobile e.g. our routes, polyfills and mobile constants.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;/web&lt;/strong&gt;&lt;br&gt;
This contains anything to do with the web frontend and will in no way touch anything to do with React Native. For example, the top level of web may look like: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;/images, /fonts&lt;/strong&gt;: and all your other static asset folders&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;/styles&lt;/strong&gt;: contains all your project styles, most likely from a preprocessor such as Sass or LESS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;/components&lt;/strong&gt;: contains all your project components, generally these components mostly just care about presentation and are stateless.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;/pages&lt;/strong&gt;: keeping pages separate from the component folder makes them easier to find.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;/project&lt;/strong&gt;: contains any none-presentational but specific config to web e.g. our routes, polyfills and web constants.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;/webpack&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Webpack takes our js, styles and other resources and bundles them into static assets, all of our build config is self contained in this folder. &lt;/p&gt;

&lt;p&gt;Rather than going too much into detail here, our webpack configs are used in our package.json scripts to either bundle our app for development or deploy minified/cachebusted files to &lt;strong&gt;/build&lt;/strong&gt; to be used in production.&lt;/p&gt;
&lt;h2&gt;
  
  
  Syncing common code between web and mobile
&lt;/h2&gt;

&lt;p&gt;For this approach to work a key part is being able to sync common code so that they are usable in web and mobile and can be updated from a single location. &lt;/p&gt;

&lt;p&gt;Since the &lt;a href="https://github.com/facebook/metro/issues/1"&gt;React Native packager doesn’t support symlinks&lt;/a&gt; we need an alternative. Even if it did support symlinks, we needed a more &lt;strong&gt;reliable&lt;/strong&gt; way keep the mobile common folder up to date without bloating web/mobile with dependencies such as gulp-watch. Making use of &lt;a href="https://github.com/wix/wml"&gt;wix's wml library&lt;/a&gt; we wrote a simple bash script that launches with xCode and ensures only one instance of this is running.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/sh

LINE=$(ps aux | grep -w "common-watch.sh" | grep -v grep | wc -l)
echo $LINE

if [ "$LINE" -le "3" ]
then
  npm install -g wml
  watchman watch ../../common
  wml add ../../common ../common-mobile
  wml start
 else
     echo "Process already running"
     exit

fi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We add a script phase to our xcode build&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PROJECTDIR="${PROJECT_DIR}"
osascript -e "tell app \"Terminal\" to do script \"cd $PROJECTDIR/../bin &amp;amp;&amp;amp; sh ../bin/common-watch.sh &amp;amp;&amp;amp; exit\""
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--e5-O6is0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/http://g.recordit.co/j6A8lIxu6s.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--e5-O6is0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/http://g.recordit.co/j6A8lIxu6s.gif" width="623" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Web and mobile Polyfilling
&lt;/h2&gt;

&lt;p&gt;To help maximise the code we reuse in our common layer, there are certain web and mobile features we might want to make available on each platform so that we don't have to worry where we use them.&lt;/p&gt;

&lt;p&gt;On web we added the following react native features to our existing pollyfil:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;AppState - sometimes we may want to know whether the browser tabs are active in the same way that apps are active.&lt;/li&gt;
&lt;li&gt;AsyncStorage - Without worrying about syntax differences we can easily local storage app state and bootstrap it to our application on a shared layer.&lt;/li&gt;
&lt;li&gt;Clipboard - having this allows us to manage the clipboard in a common place such as a higher order component.&lt;/li&gt;
&lt;li&gt;NetInfo - this allows us to write cross platform functionality that utilises the user's internet connectivity.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With the help of &lt;a href="https://github.com/necolas/react-native-web"&gt;react-native-web&lt;/a&gt; we wrapped up these modules in a simple package which can be found on our &lt;a href="https://github.com/SolidStateGroup/polyfill-react-native"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dumb and smart components
&lt;/h2&gt;

&lt;p&gt;When looking solely at our app components, using Dan Abramov's pattern of &lt;a href="https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0"&gt;smart and dumb components&lt;/a&gt; is generally a good way to separate our dumb &lt;strong&gt;/mobile&lt;/strong&gt;, &lt;strong&gt;/web&lt;/strong&gt; components and smart &lt;strong&gt;/common&lt;/strong&gt; components. &lt;/p&gt;

&lt;p&gt;Our dumb components are primarily concerned with how things look and rarely deal with state unless it's to do with UI rather than data. These components shouldn't need to care about dependencies such as flux actions or stores.&lt;/p&gt;

&lt;p&gt;Our smart components on the other hand don't usually contain markup, they deal with data and how things work and pass those results down to dumb components as props.&lt;/p&gt;

&lt;h2&gt;
  
  
  Client APIs
&lt;/h2&gt;

&lt;p&gt;In order to increase what we can do in our common layer, both web and mobile expose a global API that perform similar tasks in their own way. Common code doesn't have to worry about how each platform deals with the requests, examples of this may include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Recording analytic events when flux actions are called
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;API.recordEvent(Constants.FOO_CLICKED)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Social auth via a higher order component
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;API.auth.google().then(this.onLogin)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even in cases that are not used by common, this is quite a good idea to keep syntax familiar between platforms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Base modules
&lt;/h2&gt;

&lt;p&gt;As well as sharing modules across platforms we also split some of our modules into parts that are unlikely to change, for example our main mobile stylesheet looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import baseStyles from './base/baseStyleVariables'
export default Object.assign(
    {}, baseStyles,
    {
        //    Project specific styles and overrides
    }
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Tying it all together
&lt;/h2&gt;

&lt;p&gt;Our github project &lt;a href="https://github.com/SolidStateGroup/shared-react"&gt;shared-react&lt;/a&gt; provides a solid example of the above principles in an easy to understand way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Web entry flow
&lt;/h3&gt;

&lt;p&gt;The entry point main.js which kicks off the following&lt;br&gt;
1 - Polyfills React Native APIs we wish to use, in our case AppState, AsyncStorage, Clipboard and NetInfo.&lt;br&gt;
2 - Our API is assigned to global scope and exposes a single function recordEvent(eventName).&lt;br&gt;
3 - Imports our main style.scss, in development this supports scss hot reloading. In production this is extracted and inserted as a css link in the html head.&lt;br&gt;
4 - Initialises the project routes defined in and renders the results within the main application div.&lt;/p&gt;
&lt;h3&gt;
  
  
  Mobile entry flow
&lt;/h3&gt;

&lt;p&gt;The entry point index.js which kicks off the following&lt;br&gt;
1 - Polyfills any web APIs we wish to use, in our case we don't need any but in other instances we may use something such as &lt;a href="https://github.com/joltup/react-native-fetch-blob"&gt;react-native-fetch-blob&lt;/a&gt;.&lt;br&gt;
2 - Our API is assigned to global scope and exposes a single function recordEvent(eventName).&lt;br&gt;
3 - Uses react-native-globals to assign components like View to global scope such as View.&lt;br&gt;
4 - Exposes a few base components such H1-H6 and Flex and initialises a global stylesheet.&lt;br&gt;
5 - Registers our ExampleScreen using AppRegistry. We don't use a router in our example like on web as there are quite a few different and popular options in React Native. &lt;/p&gt;
&lt;h3&gt;
  
  
  The example application
&lt;/h3&gt;

&lt;p&gt;Our web and mobile include 1 page/screen that  store and retrieve a single field.&lt;/p&gt;

&lt;p&gt;They use an example higher order component which uses AsyncStorage to do the heavy lifting and passes down the following props:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
   &amp;lt;WrappedComponent instructions={instructions} //Instructions to the user
                    isLoading={isLoading} //Whether the storage is loading
                    isSaving={isSaving} //Whether the storage is saving
                    value={value} //The current value entered for the storage
                    save={save} //A function to save the current value
                    reset={reset} //A function to reset the stored value
                    onChange={onChange} //A function to call when the text value changes
                    success={success} //Determines whether saving was successful
                    {...this.props} //Pass all other props
                /&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this we create a simple form on web and mobile, our higher order component uses our cross platform api to record events,&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5z3IxpGt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/http://g.recordit.co/t1bqzCFFfe.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5z3IxpGt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/http://g.recordit.co/t1bqzCFFfe.gif" width="880" height="845"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>I've released over 100 apps in React Native since 2015, Ask Me Anything!</title>
      <dc:creator>Kyle Johnson</dc:creator>
      <pubDate>Tue, 21 Aug 2018 09:22:47 +0000</pubDate>
      <link>https://dev.to/kylessg/ive-released-over-100-apps-in-react-native-since-2015-ask-me-anything-1m9g</link>
      <guid>https://dev.to/kylessg/ive-released-over-100-apps-in-react-native-since-2015-ask-me-anything-1m9g</guid>
      <description></description>
      <category>ama</category>
      <category>javascript</category>
      <category>react</category>
      <category>reactnative</category>
    </item>
  </channel>
</rss>
