<?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: Nilesh Gadekar</title>
    <description>The latest articles on DEV Community by Nilesh Gadekar (@salttechno).</description>
    <link>https://dev.to/salttechno</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%2F439566%2F6621bfdd-fdf0-41e2-973a-e2db182262e9.png</url>
      <title>DEV Community: Nilesh Gadekar</title>
      <link>https://dev.to/salttechno</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/salttechno"/>
    <language>en</language>
    <item>
      <title>[Boost]</title>
      <dc:creator>Nilesh Gadekar</dc:creator>
      <pubDate>Wed, 03 Dec 2025 15:09:16 +0000</pubDate>
      <link>https://dev.to/salttechno/-57o2</link>
      <guid>https://dev.to/salttechno/-57o2</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/salttechno" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F439566%2F6621bfdd-fdf0-41e2-973a-e2db182262e9.png" alt="salttechno"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/salttechno/migrate-your-wordpress-blog-to-sanity-in-an-afternoon-open-source-tool-2ga" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Migrate your WordPress blog to Sanity in an afternoon (open-source tool)&lt;/h2&gt;
      &lt;h3&gt;Nilesh Gadekar ・ Dec 2 '25&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#wordpress&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#sanity&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#opensource&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#github&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>wordpress</category>
      <category>sanity</category>
      <category>opensource</category>
      <category>github</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Nilesh Gadekar</dc:creator>
      <pubDate>Wed, 03 Dec 2025 05:52:28 +0000</pubDate>
      <link>https://dev.to/salttechno/-57fi</link>
      <guid>https://dev.to/salttechno/-57fi</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/salttechno" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F439566%2F6621bfdd-fdf0-41e2-973a-e2db182262e9.png" alt="salttechno"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/salttechno/migrate-your-wordpress-blog-to-sanity-in-an-afternoon-open-source-tool-2ga" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Migrate your WordPress blog to Sanity in an afternoon (open-source tool)&lt;/h2&gt;
      &lt;h3&gt;Nilesh Gadekar ・ Dec 2 '25&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#wordpress&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#sanity&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#opensource&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#github&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>wordpress</category>
      <category>sanity</category>
      <category>opensource</category>
      <category>github</category>
    </item>
    <item>
      <title>Migrate your WordPress blog to Sanity in an afternoon (open-source tool)</title>
      <dc:creator>Nilesh Gadekar</dc:creator>
      <pubDate>Tue, 02 Dec 2025 16:59:14 +0000</pubDate>
      <link>https://dev.to/salttechno/migrate-your-wordpress-blog-to-sanity-in-an-afternoon-open-source-tool-2ga</link>
      <guid>https://dev.to/salttechno/migrate-your-wordpress-blog-to-sanity-in-an-afternoon-open-source-tool-2ga</guid>
      <description>&lt;p&gt;If you're running your blog on WordPress but building your frontend with modern stacks like Next.js, Remix, or Astro, Sanity can be a much better home for your content. Structured content, Portable Text, powerful querying, real-time collaboration… all the good stuff.&lt;/p&gt;

&lt;p&gt;The problem: actually &lt;em&gt;moving&lt;/em&gt; your WordPress content into Sanity is usually the painful bit.&lt;/p&gt;

&lt;p&gt;Most guides show you how to &lt;strong&gt;write your own migration script&lt;/strong&gt; from scratch. We did that work, battle-tested it on real blogs, and then open-sourced the tool so you don’t have to reinvent the wheel:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/salttechno/wp-to-sanity-migration" rel="noopener noreferrer"&gt;https://github.com/salttechno/wp-to-sanity-migration&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This post walks you through what it does and how to use it.&lt;/p&gt;




&lt;h2&gt;
  
  
  What this tool does for you
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;WordPress to Sanity Blog Migration Tool&lt;/strong&gt; is a Node.js-based CLI that talks to the WordPress REST API and pushes everything into Sanity in a structured way.&lt;/p&gt;

&lt;p&gt;Out of the box, it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Migrates &lt;strong&gt;posts&lt;/strong&gt;, &lt;strong&gt;categories&lt;/strong&gt;, &lt;strong&gt;tags&lt;/strong&gt;, and &lt;strong&gt;media (images)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;✅ Converts WordPress HTML content to &lt;strong&gt;Portable Text&lt;/strong&gt; for richer editing and rendering&lt;/li&gt;
&lt;li&gt;✅ Preserves &lt;strong&gt;relationships&lt;/strong&gt; (categories, tags, featured images)&lt;/li&gt;
&lt;li&gt;✅ Uploads images into Sanity’s asset pipeline&lt;/li&gt;
&lt;li&gt;✅ Is &lt;strong&gt;idempotent&lt;/strong&gt; – safe to run multiple times (no duplicate docs)&lt;/li&gt;
&lt;li&gt;✅ Ships with a ready-to-use &lt;strong&gt;Sanity Studio&lt;/strong&gt; configured for the migrated content&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s focused on &lt;strong&gt;blog migration&lt;/strong&gt; first, but you can extend it to pages, custom post types, authors, etc.&lt;/p&gt;




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

&lt;p&gt;You’ll need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node.js 18+&lt;/li&gt;
&lt;li&gt;A WordPress site with the REST API enabled (default for WP 4.7+)&lt;/li&gt;
&lt;li&gt;A Sanity project (free tier is enough)&lt;/li&gt;
&lt;li&gt;A Sanity API token with write access&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you can open:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;https://your-site.com/wp-json/wp/v2/posts&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;in your browser, you’re good on the WordPress side.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick start: migrate your blog in a few steps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Clone the repo and install dependencies
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/salttechno/wp-to-sanity-migration.git
&lt;span class="nb"&gt;cd &lt;/span&gt;wp-to-sanity-migration
npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Configure your &lt;code&gt;.env&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Copy the example env file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cp&lt;/span&gt; .env.example .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then edit &lt;code&gt;.env&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# WordPress Configuration&lt;/span&gt;
&lt;span class="nv"&gt;WP_API_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://your-wordpress-site.com/wp-json/wp/v2

&lt;span class="c"&gt;# Sanity Configuration&lt;/span&gt;
&lt;span class="nv"&gt;SANITY_PROJECT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-project-id
&lt;span class="nv"&gt;SANITY_DATASET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production
&lt;span class="nv"&gt;SANITY_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-write-token
&lt;span class="nv"&gt;SANITY_API_VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2024-11-25
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Tip: you’ll find your &lt;strong&gt;Project ID&lt;/strong&gt; and can generate a &lt;strong&gt;token&lt;/strong&gt; in &lt;code&gt;sanity.io/manage&lt;/code&gt; under your project’s settings.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  3. Test connections
&lt;/h3&gt;

&lt;p&gt;Before importing anything, verify both sides are reachable:&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 &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This checks that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WordPress REST API is reachable&lt;/li&gt;
&lt;li&gt;Sanity credentials and token are valid&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Run the migration
&lt;/h3&gt;

&lt;p&gt;Now the fun part:&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 migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Behind the scenes, the script:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fetches categories
&lt;/li&gt;
&lt;li&gt;Fetches tags
&lt;/li&gt;
&lt;li&gt;Fetches media (images) and uploads them to Sanity
&lt;/li&gt;
&lt;li&gt;Fetches posts and creates/updates corresponding Sanity documents, wiring up all relationships&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The migration is &lt;strong&gt;idempotent&lt;/strong&gt;, so you can safely re-run it while tweaking schemas or content mapping.&lt;/p&gt;




&lt;h2&gt;
  
  
  Browse your content in Sanity Studio
&lt;/h2&gt;

&lt;p&gt;The repo also includes a preconfigured Sanity Studio in the the &lt;code&gt;studio/&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;From the project root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;studio
npm &lt;span class="nb"&gt;install
cp&lt;/span&gt; .env.example .env   &lt;span class="c"&gt;# add your Sanity project details&lt;/span&gt;
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

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

&lt;/div&gt;



&lt;p&gt;You’ll see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;Post&lt;/strong&gt; schema with Portable Text fields&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Categories&lt;/strong&gt; and &lt;strong&gt;Tags&lt;/strong&gt; linked via references&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Featured images&lt;/strong&gt; wired up as Sanity image assets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can deploy the Studio as well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;studio
npm run deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sanity will give you a hosted Studio URL like &lt;code&gt;your-blog.sanity.studio&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  How the migration works under the hood
&lt;/h2&gt;

&lt;p&gt;If you’re curious (or planning to extend it), here’s the rough architecture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;wordpress-client.js&lt;/code&gt;&lt;br&gt;&lt;br&gt;
Talks to the WordPress REST API, fetches posts, categories, tags, and media.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;sanity-client.js&lt;/code&gt;&lt;br&gt;&lt;br&gt;
Uses &lt;code&gt;@sanity/client&lt;/code&gt; to create or replace documents in Sanity.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;html-to-blocks.js&lt;/code&gt;&lt;br&gt;&lt;br&gt;
Converts HTML from WordPress into Portable Text blocks, so your editors aren’t stuck editing raw HTML.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;transformers.js&lt;/code&gt;&lt;br&gt;&lt;br&gt;
Maps WordPress entities into Sanity document shapes: posts → &lt;code&gt;post&lt;/code&gt;, terms → &lt;code&gt;category&lt;/code&gt; / &lt;code&gt;tag&lt;/code&gt;, media → &lt;code&gt;image&lt;/code&gt; assets.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;migrate.js&lt;/code&gt;&lt;br&gt;&lt;br&gt;
Orchestrates the whole process in the right order and ensures it’s safe to re-run.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes it easy to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add new content types (e.g. &lt;strong&gt;case studies&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;Plug in custom fields&lt;/li&gt;
&lt;li&gt;Change schema names or structures on the Sanity side&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What gets migrated (and what doesn’t)
&lt;/h2&gt;

&lt;p&gt;Out of the box, the tool handles:&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Posts&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Title, slug, published date
&lt;/li&gt;
&lt;li&gt;Body content → Portable Text
&lt;/li&gt;
&lt;li&gt;Excerpt → Portable Text
&lt;/li&gt;
&lt;li&gt;Featured image
&lt;/li&gt;
&lt;li&gt;Categories &amp;amp; tags&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ &lt;strong&gt;Categories &amp;amp; Tags&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All your post categories and tags, with relationships preserved&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ &lt;strong&gt;Media (images)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Images referenced from posts are uploaded into Sanity as proper image assets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By default, it &lt;strong&gt;does not&lt;/strong&gt; migrate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pages&lt;/li&gt;
&lt;li&gt;Authors&lt;/li&gt;
&lt;li&gt;Comments&lt;/li&gt;
&lt;li&gt;Custom post types&lt;/li&gt;
&lt;li&gt;WordPress-specific metadata&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The point is to give you a &lt;strong&gt;clean, production-ready baseline&lt;/strong&gt; for blog content, not an opaque black box that tries to handle every plugin and edge case.&lt;/p&gt;




&lt;h2&gt;
  
  
  Extending it: pages, authors, custom post types
&lt;/h2&gt;

&lt;p&gt;You can absolutely extend this for more advanced setups.&lt;/p&gt;

&lt;p&gt;Some ideas:&lt;/p&gt;

&lt;h3&gt;
  
  
  Pages
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Add a &lt;code&gt;page&lt;/code&gt; schema to &lt;code&gt;studio/schemas/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add a new fetch function in &lt;code&gt;wordpress-client.js&lt;/code&gt; for &lt;code&gt;pages&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Create a page transformer in &lt;code&gt;transformers.js&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Wire it into &lt;code&gt;migrate.js&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Authors
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Fetch authors from the WordPress API&lt;/li&gt;
&lt;li&gt;Add an &lt;code&gt;author&lt;/code&gt; schema (already included as an optional type)&lt;/li&gt;
&lt;li&gt;Link authors in the post transformer&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Custom post types
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Create additional WordPress client functions (e.g. &lt;code&gt;getCaseStudies()&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Add a corresponding schema in Studio&lt;/li&gt;
&lt;li&gt;Create a transformer and call it from the migration script&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There’s even an example branch in the repo that shows how to handle a custom post type.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common gotchas (and how to fix them)
&lt;/h2&gt;

&lt;p&gt;Some issues you might hit:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. “Cannot connect to WordPress API”
&lt;/h3&gt;

&lt;p&gt;Check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is &lt;code&gt;WP_API_URL&lt;/code&gt; correct?&lt;/li&gt;
&lt;li&gt;Can you open &lt;code&gt;&amp;lt;WP_API_URL&amp;gt;/posts&lt;/code&gt; in your browser?&lt;/li&gt;
&lt;li&gt;Is your WP site behind auth or a firewall?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. “Sanity connection failed”
&lt;/h3&gt;

&lt;p&gt;Verify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;SANITY_PROJECT_ID&lt;/code&gt; matches your actual project&lt;/li&gt;
&lt;li&gt;Token has read + write permissions&lt;/li&gt;
&lt;li&gt;Token hasn’t been revoked or expired&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. “Invalid image, could not read metadata”
&lt;/h3&gt;

&lt;p&gt;This usually means there are corrupted or weird images in your WordPress media library. The script logs these but doesn’t fail the entire migration—fix them later if needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. “JavaScript heap out of memory”
&lt;/h3&gt;

&lt;p&gt;For very large sites, bump Node’s memory limit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;NODE_OPTIONS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"--max-old-space-size=4096"&lt;/span&gt; npm run migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Plugging into your frontend
&lt;/h2&gt;

&lt;p&gt;Once your content lives in Sanity, you can query it with GROQ and render with your framework of choice.&lt;/p&gt;

&lt;p&gt;Example GROQ query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*[_type == "post"] | order(publishedAt desc) {
  title,
  slug,
  publishedAt,
  excerpt,
  body,
  featuredImage,
  categories[]-&amp;gt;,
  tags[]-&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example React/Next.js component with Portable Text:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&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;PortableText&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;@portabletext/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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;BlogPost&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;post&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;article&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PortableText&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;article&lt;/span&gt;&lt;span class="p"&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;From here, all the usual headless/modern-stack benefits kick in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Static generation or ISR&lt;/li&gt;
&lt;li&gt;Custom designs per post type&lt;/li&gt;
&lt;li&gt;Multi-channel publishing&lt;/li&gt;
&lt;li&gt;Better performance and SEO than a typical WP theme stack&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why we open-sourced it
&lt;/h2&gt;

&lt;p&gt;We originally built this tool to migrate a real production blog to Sanity, without spending days writing one-off scripts and dealing with partial imports.&lt;/p&gt;

&lt;p&gt;Instead of leaving it as an internal script, we decided to clean it up, document it properly, and release it under the &lt;strong&gt;MIT license&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Are stuck on WordPress but want Sanity for content&lt;/li&gt;
&lt;li&gt;Don’t want to maintain fragile one-off migration scripts&lt;/li&gt;
&lt;li&gt;Prefer a starting point you can hack on&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;…this repo should save you a lot of time.&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Check it out, try it, and star it if it helps:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/salttechno/wp-to-sanity-migration" rel="noopener noreferrer"&gt;https://github.com/salttechno/wp-to-sanity-migration&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Maintainers &amp;amp; support
&lt;/h2&gt;

&lt;p&gt;This project is maintained by &lt;strong&gt;Salt Technologies&lt;/strong&gt;, a software outsourcing company in India that builds modern web apps, headless CMS projects, and data/AI-powered platforms for clients across the globe.&lt;/p&gt;

&lt;p&gt;🌐 &lt;strong&gt;&lt;a href="https://www.salttechno.com/" rel="noopener noreferrer"&gt;Software Outsourcing Company in India – Salt Technologies&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you run into issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open a GitHub issue on the repo&lt;/li&gt;
&lt;li&gt;Share ideas for improvements (custom post types, progress UI, auth support, etc.)&lt;/li&gt;
&lt;li&gt;Or open a PR if you’ve already solved a problem others might hit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy migrating 🚀&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>sanity</category>
      <category>opensource</category>
      <category>github</category>
    </item>
    <item>
      <title>How To Make Remote &amp; Outsourced Dev Teams Actually Work (From a Developer’s POV)</title>
      <dc:creator>Nilesh Gadekar</dc:creator>
      <pubDate>Tue, 02 Dec 2025 11:57:27 +0000</pubDate>
      <link>https://dev.to/salttechno/how-to-make-remote-outsourced-dev-teams-actually-work-from-a-developers-pov-4dp9</link>
      <guid>https://dev.to/salttechno/how-to-make-remote-outsourced-dev-teams-actually-work-from-a-developers-pov-4dp9</guid>
      <description>&lt;p&gt;Remote and outsourced dev teams are no longer “special cases” – for many companies, that &lt;em&gt;is&lt;/em&gt; the engineering org.&lt;/p&gt;

&lt;p&gt;But if you’ve ever worked with a team in another country or time zone, you already know the pain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Half-baked tickets
&lt;/li&gt;
&lt;li&gt;Confusing handovers
&lt;/li&gt;
&lt;li&gt;Slack pings at weird hours
&lt;/li&gt;
&lt;li&gt;Endless “Can you clarify this?” messages
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a developer who’s worked both &lt;strong&gt;inside&lt;/strong&gt; an outsourcing company and &lt;strong&gt;with&lt;/strong&gt; clients’ in-house teams, I’ve seen the good, the bad, and the chaotic.&lt;/p&gt;

&lt;p&gt;This post is for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Devs in US/EU companies who work with offshore/outsourced teams
&lt;/li&gt;
&lt;li&gt;Devs in India/other regions who are part of those outsourced teams
&lt;/li&gt;
&lt;li&gt;Tech leads trying to make this collaboration less painful for everyone
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’m not going to talk about “cost savings” or “rates”. This is purely about &lt;strong&gt;how to collaborate better as engineers&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Treat outsourced teams as part of the engineering org, not a ticket factory
&lt;/h2&gt;

&lt;p&gt;The biggest mistake I see: outsourced teams are treated like a Jira vending machine.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Here are the tickets. Just build it.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That kills ownership and quality.&lt;/p&gt;

&lt;p&gt;Instead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Share the why, not just the what.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Add a small “Context / Problem” section in tickets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What’s the business goal?&lt;/li&gt;
&lt;li&gt;What metric does this impact?&lt;/li&gt;
&lt;li&gt;What’s the user story behind this feature?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Invite them to tech discussions.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Even if time zones don’t align, share:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Architecture diagrams
&lt;/li&gt;
&lt;li&gt;ADRs (Architecture Decision Records)
&lt;/li&gt;
&lt;li&gt;Loom videos summarizing decisions
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Let them disagree.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;
If the remote team cannot say, “This design will cause scaling issues later,” you don’t have a partnership — you have outsourced typing.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Write async-friendly tickets (this alone can save days per sprint)
&lt;/h2&gt;

&lt;p&gt;When you work across time zones, every “quick clarification” can cost 12–24 hours.&lt;/p&gt;

&lt;p&gt;Good tickets are an &lt;em&gt;engineering productivity tool&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;A simple structure that works really well:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Context&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Short paragraph on business goal
&lt;/li&gt;
&lt;li&gt;Links to Notion/Confluence/specs
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Requirements&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bullet out expected behavior
&lt;/li&gt;
&lt;li&gt;Cover edge cases (empty states, error states, permissions, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. UX/UI&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Link Figma/Designs
&lt;/li&gt;
&lt;li&gt;Mention which parts are “must match exactly” vs “flexible”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4. Technical Notes (optional)&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Existing APIs / DB tables / models
&lt;/li&gt;
&lt;li&gt;Performance constraints
&lt;/li&gt;
&lt;li&gt;Feature flags, logging requirements
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;5. Acceptance Criteria&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“Given / When / Then” style works great:

&lt;ul&gt;
&lt;li&gt;Given I am a logged-in user
&lt;/li&gt;
&lt;li&gt;When I click “Download report”
&lt;/li&gt;
&lt;li&gt;Then a CSV is generated and emailed within 5 minutes
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;If your outsourced team receives tickets like this, you’ll see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fewer clarifications
&lt;/li&gt;
&lt;li&gt;Fewer reworks
&lt;/li&gt;
&lt;li&gt;Better estimates
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And yes, your future self will also thank you.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Over-communicate the “definition of done”
&lt;/h2&gt;

&lt;p&gt;“Done” is one of the most overloaded words in software.&lt;/p&gt;

&lt;p&gt;For one team, “done” = code pushed.&lt;br&gt;&lt;br&gt;
For another, “done” = in production, dashboards green, docs updated.&lt;/p&gt;

&lt;p&gt;To avoid surprises with remote teams, &lt;strong&gt;make DoD explicit&lt;/strong&gt;. For example:&lt;/p&gt;

&lt;p&gt;A feature is &lt;em&gt;done&lt;/em&gt; only when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code merged to &lt;code&gt;main&lt;/code&gt; (after review)
&lt;/li&gt;
&lt;li&gt;Unit tests + basic integration tests added
&lt;/li&gt;
&lt;li&gt;Linting &amp;amp; formatter pass
&lt;/li&gt;
&lt;li&gt;Feature behind a flag (if needed)
&lt;/li&gt;
&lt;li&gt;Monitoring/logging added (if relevant)
&lt;/li&gt;
&lt;li&gt;Basic docs / README update
&lt;/li&gt;
&lt;li&gt;Deployed to staging / production (depending on your process)
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Document this once. Link it in every sprint kickoff.&lt;br&gt;&lt;br&gt;
It feels “process heavy”, but it &lt;strong&gt;reduces arguments and friction&lt;/strong&gt; later.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Use pull requests as collaboration, not just gates
&lt;/h2&gt;

&lt;p&gt;When working with an outsourced team, PRs can easily turn into:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Fix this. Change that. Why did you do this?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Which feels like a police inspection more than a review.&lt;/p&gt;

&lt;p&gt;Instead, try:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ask curious questions instead of accusations&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ “Why did you do it like this?”
&lt;/li&gt;
&lt;li&gt;✅ “Can you help me understand the trade-offs you considered here?”&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Suggest, don’t dictate&lt;/strong&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;
Use GitHub suggestions where possible:&lt;br&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  - const limit = 50;
  + const limit = 100; // matches product requirement for max items/page
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Review structure, not just syntax&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does the code follow architecture guidelines?
&lt;/li&gt;
&lt;li&gt;Are we duplicating logic?
&lt;/li&gt;
&lt;li&gt;Are there security or performance concerns?
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Time-box review cycles&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Remote teams often sit blocked on reviews. Define:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“PRs &amp;lt; 200 LOC → review within 24 hours”
&lt;/li&gt;
&lt;li&gt;“Larger PRs → split or schedule a review session”
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Good review culture turns outsourced devs into &lt;strong&gt;true teammates&lt;/strong&gt;, not “external vendors”.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Respect time zones &lt;em&gt;and&lt;/em&gt; create overlap on purpose
&lt;/h2&gt;

&lt;p&gt;Healthy remote collaboration = async-first, but not async-only.&lt;/p&gt;

&lt;p&gt;Some practical tips:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Define overlap hours clearly&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Even 1–2 hours of overlap can unblock a week’s worth of work.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Use the overlap for the right things&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sprint planning
&lt;/li&gt;
&lt;li&gt;Architecture discussions
&lt;/li&gt;
&lt;li&gt;“Gray area” decisions
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Don’t waste overlap hours on things that could have been documented.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Be very intentional about meetings&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Share agenda in advance
&lt;/li&gt;
&lt;li&gt;Record calls
&lt;/li&gt;
&lt;li&gt;Summarize decisions in writing
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  6. Share your engineering standards openly
&lt;/h2&gt;

&lt;p&gt;If you’re the client / in-house team:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Share your &lt;strong&gt;coding guidelines&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Share &lt;strong&gt;folder structure patterns&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Share &lt;strong&gt;testing philosophy&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Share how you like:

&lt;ul&gt;
&lt;li&gt;Logging
&lt;/li&gt;
&lt;li&gt;Error handling
&lt;/li&gt;
&lt;li&gt;Observability
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;If you’re the outsourced team:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ask for these explicitly.
&lt;/li&gt;
&lt;li&gt;If they don’t exist, propose a starter version.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This avoids the situation where both teams build the same thing… differently.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Things I’ve seen go wrong (that you can avoid)
&lt;/h2&gt;

&lt;p&gt;A few recurring anti-patterns:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;“Let’s give them only the boring work.”&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
→ You end up with a demotivated team and low-quality code in critical but “unsexy” areas.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;“We’ll fix the architecture later.”&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
→ Spoiler: you won’t. Once multiple teams are building on top of it, your options shrink.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Only talking to project managers, never to engineers.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
→ Information gets distorted. Engineers are forced to guess.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Rotating outsourced vendors frequently.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
→ You lose product context each time. You save nothing in the long run.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Treating every outsourced team as disposable.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
→ The best devs don’t want to work in environments where they’re treated that way.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  8. If you’re a developer inside an outsourcing company
&lt;/h2&gt;

&lt;p&gt;A few tips for you too:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Act like an owner, not a contractor&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ask about business goals
&lt;/li&gt;
&lt;li&gt;Proactively flag risks
&lt;/li&gt;
&lt;li&gt;Suggest simplifications
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Build trust with consistency&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hit deadlines (or communicate early if you can’t)
&lt;/li&gt;
&lt;li&gt;Don’t surprise your client with silent delays
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Invest in communication skills&lt;/strong&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;
Your English, writing, and clarity matter almost as much as your code.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Document more than you think you need&lt;/strong&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;
The next dev (maybe you in three months) will thank you.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  9. Wrapping up
&lt;/h2&gt;

&lt;p&gt;Remote + outsourced collaboration doesn’t have to be painful.&lt;/p&gt;

&lt;p&gt;If you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Share context, not just tasks
&lt;/li&gt;
&lt;li&gt;Write async-friendly tickets
&lt;/li&gt;
&lt;li&gt;Make “done” explicit
&lt;/li&gt;
&lt;li&gt;Use PRs as collaboration, not punishment
&lt;/li&gt;
&lt;li&gt;Respect time zones while creating intentional overlap
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;…you can turn “outsourced team” into &lt;strong&gt;“distributed engineering org that actually ships.”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you’re ever exploring working with a &lt;strong&gt;&lt;a href="https://www.salttechno.com/" rel="noopener noreferrer"&gt;Software Outsourcing Company in India&lt;/a&gt;&lt;/strong&gt; and want teams that care about code quality, communication, and long-term product health, feel free to check us out — but regardless of who you work with, I hope this post helps you build better remote collaborations.&lt;/p&gt;

</description>
      <category>softwaredevelopment</category>
      <category>softwareoutsourcing</category>
      <category>remote</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to Choose the Best Headless CMS for Your Jamstack Project</title>
      <dc:creator>Nilesh Gadekar</dc:creator>
      <pubDate>Fri, 06 Jan 2023 05:45:30 +0000</pubDate>
      <link>https://dev.to/salttechno/how-to-choose-the-best-headless-cms-for-your-jamstack-project-32f</link>
      <guid>https://dev.to/salttechno/how-to-choose-the-best-headless-cms-for-your-jamstack-project-32f</guid>
      <description>&lt;p&gt;As a developer or business owner, you know the importance of choosing the right tools for your project. When it comes to building a Jamstack website or application, one of the key decisions you'll need to make is which headless content management system (CMS) to use.&lt;/p&gt;

&lt;p&gt;With so many options available, it can be overwhelming to determine which CMS is the best fit for your project. Here are a few key factors to consider when evaluating headless CMS options for your Jamstack project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Features and functionality:&lt;/strong&gt; The first thing you'll want to consider is what features and functionality you need from your CMS. Do you need support for multiple languages? Do you need advanced content modeling capabilities? Do you need a user-friendly interface for content authors? Make a list of your must-have features and use it as a starting point for evaluating different CMS options.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API-first approach:&lt;/strong&gt; As a Jamstack developer, you'll be relying on APIs to fetch and deliver content to your website or application. It's important to choose a CMS that has a robust, well-documented API that makes it easy to retrieve and manipulate content.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability:&lt;/strong&gt; As your website or application grows, you'll need a CMS that can scale along with it. Consider the CMS's track record for handling large amounts of traffic and data, as well as any built-in scalability features it may offer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pricing:&lt;/strong&gt; Don't forget to factor in cost when evaluating CMS options. While you don't want to skimp on quality, you also don't want to overspend on a CMS that offers more features than you need. Determine your budget and look for a CMS that fits within it while still meeting your project's requirements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community and support:&lt;/strong&gt; Finally, consider the level of support and community resources available for the CMS you're considering. A strong community of developers and users can be a valuable resource for troubleshooting issues and learning about new features and best practices.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, which headless CMS is right for your Jamstack project? Here are a few popular options to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Contentful:&lt;/strong&gt; Contentful is a feature-rich CMS with a focus on flexibility and ease of use. It offers a wide range of features, including support for multiple languages, advanced content modeling, and a user-friendly interface for content authors. Its API is well-documented and easy to work with, making it a popular choice for developers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sanity:&lt;/strong&gt; Sanity is a open-source CMS that is popular for its simplicity and flexibility. It offers a user-friendly interface for content authors and a powerful API for developers. Its schema-based content modeling system allows for advanced customization, making it a good fit for projects with unique content requirements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Netlify CMS:&lt;/strong&gt; Netlify CMS is an open-source CMS that is tightly integrated with the popular static site hosting service, Netlify. It offers a user-friendly interface for content authors and a Git-based workflow for developers. Its focus on simplicity makes it a good choice for smaller projects or teams.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Headless WordPress:&lt;/strong&gt; While WordPress is primarily known as a traditional, monolithic CMS, it can also be used in a headless configuration. In a headless setup, WordPress serves as a backend API, providing content to your Jamstack frontend via its REST API. This allows you to take advantage of WordPress's rich feature set while still leveraging the benefits of the Jamstack architecture.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By considering these factors, you can narrow down your options and choose the best headless CMS for your Jamstack project. With the right tools in place, you'll be well on your way to building a successful website or application.&lt;/p&gt;

&lt;p&gt;Bonus Tip: Don't forget to check out &lt;a href="https://www.jamrix.com" rel="noopener noreferrer"&gt;Jamrix&lt;/a&gt;, a leading Jamstack development agency. Our team of experts can help you choose the best CMS for your project and guide you through the development process from start to finish. Contact us today to learn mo&lt;/p&gt;

</description>
      <category>jamstack</category>
      <category>headless</category>
      <category>cms</category>
    </item>
    <item>
      <title>Streamlining My Business Website with the Jamstack: A Case Study</title>
      <dc:creator>Nilesh Gadekar</dc:creator>
      <pubDate>Sat, 17 Dec 2022 12:55:57 +0000</pubDate>
      <link>https://dev.to/salttechno/streamlining-my-business-website-with-the-jamstack-a-case-study-41f4</link>
      <guid>https://dev.to/salttechno/streamlining-my-business-website-with-the-jamstack-a-case-study-41f4</guid>
      <description>&lt;p&gt;As the owner of a &lt;a href="https://www.salttechno.com" rel="noopener noreferrer"&gt;software development company&lt;/a&gt;, I know firsthand how important it is to have a professional and user-friendly website. That's why when I decided to redesign my business website, I knew I wanted to find a platform that was fast, scalable, and secure. After doing some research, I decided to rebuild my website on the Jamstack using SvelteKit.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the Jamstack?
&lt;/h2&gt;

&lt;p&gt;For those who may not be familiar, the Jamstack is a modern web development architecture that involves building websites and apps using JavaScript, APIs, and Markup. One of the key benefits of the Jamstack is that it allows for faster performance and lower hosting costs compared to traditional server-rendered websites.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I Chose the Jamstack
&lt;/h2&gt;

&lt;p&gt;When I first started using WordPress for my business website, I was impressed by its flexibility and the wide range of plugins available. However, as my business grew and I started receiving more traffic, I began to experience issues with the website's speed and stability. I also found that managing and updating the website was becoming increasingly time-consuming.&lt;/p&gt;

&lt;p&gt;That's when I started looking into alternative platforms for my business website. After considering a few options, I decided to rebuild my website on the Jamstack using SvelteKit, a new and innovative framework for building serverless web applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Benefits of the Jamstack
&lt;/h2&gt;

&lt;p&gt;In addition to the improved performance and lower costs, the Jamstack offers a number of other benefits that are particularly relevant for businesses.&lt;/p&gt;

&lt;p&gt;First, the Jamstack offers &lt;strong&gt;improved security&lt;/strong&gt;. Because static sites are not dynamically generated, they are less vulnerable to certain types of attacks such as SQL injection. Additionally, static sites can be served over SSL with minimal effort, which helps to protect sensitive information such as login credentials and credit card numbers.&lt;/p&gt;

&lt;p&gt;Second, the Jamstack is &lt;strong&gt;highly scalable&lt;/strong&gt;. Because static sites can be easily scaled up or down as needed, they can handle sudden spikes in traffic without breaking a sweat. This is especially important for businesses that may experience seasonal or event-related spikes in traffic.&lt;/p&gt;

&lt;p&gt;Finally, the Jamstack is &lt;strong&gt;flexible and customizable&lt;/strong&gt;. With a wide range of tools and frameworks available, it's easy to tailor your website to meet the specific needs of your business. And because static sites are pre-built, it's easy to make changes and updates without affecting the performance of the site.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Experience with the Jamstack
&lt;/h2&gt;

&lt;p&gt;I've been extremely happy with my decision to rebuild my business website on the Jamstack using SvelteKit. The framework's developer experience is top-notch, and I've found the build process to be smooth and efficient. The improved performance and lower costs have also been a major benefit, and I've received positive feedback from my website visitors about the faster loading times.&lt;/p&gt;

&lt;p&gt;If you're considering a redesign for your business website, I highly recommend giving the Jamstack a closer look. Whether you're a small business owner or a large corporation, the benefits of the Jamstack are hard to ignore. And with a growing number of tools and frameworks available, it's never been easier to get started.&lt;/p&gt;

</description>
      <category>emptystring</category>
    </item>
    <item>
      <title>How to setup Tailwind CSS with PostCSS &amp; Browsersync?</title>
      <dc:creator>Nilesh Gadekar</dc:creator>
      <pubDate>Mon, 01 Mar 2021 18:38:54 +0000</pubDate>
      <link>https://dev.to/salttechno/how-to-setup-tailwind-css-with-postcss-browsersync-1j41</link>
      <guid>https://dev.to/salttechno/how-to-setup-tailwind-css-with-postcss-browsersync-1j41</guid>
      <description>&lt;p&gt;So, you want to start using Tailwind CSS for your next HTML project but don't know how to set it up with PostCSS &amp;amp; Browsersync? Please read this post till the end to start using it easily.&lt;/p&gt;

&lt;p&gt;We will see how you can use Gulp js to automate browser reload on file saving, create an optimized version of Tailwind CSS, and optimize production images.&lt;/p&gt;

&lt;p&gt;Tailwind CSS output needs to be optimized for production use. The development version for the CSS file is almost 4MB which is not good for production websites. &lt;a href="https://tailwindcss.com/docs/optimizing-for-production" rel="noopener noreferrer"&gt;Read this for more details&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So, ideally, you need an editable full version of Tailwind CSS while developing the project. And you need to optimize it for production. We also need to configure the server to watch our files for changes &amp;amp; reload the browser automatically after updates.&lt;/p&gt;

&lt;p&gt;We will use gulp js for the automation to enhance our workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  What will we achieve in the end?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Launch development environment with browser auto-refresh &amp;amp; browser auto-sync&lt;/li&gt;
&lt;li&gt;Customize Tailwind CSS configuration as per your needs&lt;/li&gt;
&lt;li&gt;Build the optimized production version of Tailwind CSS&lt;/li&gt;
&lt;li&gt;Optimize all images for production&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;You can find the following code on GitHub as &lt;a href="https://github.com/salttechno/tailwindcss-boilerplate" rel="noopener noreferrer"&gt;Tailwind CSS Boilerplate&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's start.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Setup
&lt;/h2&gt;

&lt;p&gt;Create a new directory and open it in VS Code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;tailwind-starter
&lt;span class="nb"&gt;cd &lt;/span&gt;tailwind-starter
code &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install latest Tailwind CSS &amp;amp; dependencies.&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;-D&lt;/span&gt; tailwindcss@latest postcss@latest autoprefixer@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember that Tailwind CSS requires Node.js 12.13.0 or higher.&lt;/p&gt;

&lt;p&gt;Next, let's generate our &lt;code&gt;tailwind.config.js&lt;/code&gt; and &lt;code&gt;postcss.config.js&lt;/code&gt; files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx tailwindcss init &lt;span class="nt"&gt;-p&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PostCSS works as our preprocessor here. It will compile our Tailwind CSS file. We will use the &lt;code&gt;tailwind.config.js&lt;/code&gt; file for configuring our Tailwind.&lt;/p&gt;

&lt;p&gt;The first thing we will configure is the purge settings. Add our CSS files &amp;amp; HTML files in an array for purge settings. These are the locations where we will be using Tailwind classes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// tailwind.config.js&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;purge&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;./src/**/*.css&lt;/span&gt;&lt;span class="dl"&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;./**/*.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;darkMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// or 'media' or 'class'&lt;/span&gt;
    &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;extend&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;variants&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;extend&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;plugins&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can use this same file for any customization with our Tailwind CSS. Refer to &lt;a href="https://tailwindcss.com/docs/configuration" rel="noopener noreferrer"&gt;this link&lt;/a&gt; to learn more about customization settings.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding CSS &amp;amp; HTML files
&lt;/h3&gt;

&lt;p&gt;Now, let's add a CSS file first where we will inject tailwind directives.&lt;/p&gt;

&lt;p&gt;Create an &lt;code&gt;src&lt;/code&gt; folder in our project's root directory. Add a new file in this directory and name it &lt;code&gt;styles.css.&lt;/code&gt; Add the following content to the newly created CSS file. To learn more about this, refer to &lt;a href="https://tailwindcss.com/docs/installation#include-tailwind-in-your-css" rel="noopener noreferrer"&gt;this link&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* ./src/styles.css */&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="err"&gt;@apply&lt;/span&gt; &lt;span class="err"&gt;bg-white&lt;/span&gt; &lt;span class="err"&gt;text-gray-700;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;utilities&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a new folder in our project's root directory named &lt;code&gt;assets&lt;/code&gt;. We will be using this folder for storing all assets required in the project. Within this new folder, create separate folders for &lt;code&gt;css&lt;/code&gt; &amp;amp; &lt;code&gt;images&lt;/code&gt;. The compiled version of our CSS file will be stored in this folder by gulp task.&lt;/p&gt;

&lt;p&gt;Now, let's add our &lt;code&gt;index.html&lt;/code&gt; in the root directory and include the compiled CSS file's path.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- index.html --&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/assets/css/styles.css"&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;
            Tailwind CSS Boilerplate (PostCSS + Browsersync + Gulp 4 + Imagemin)
        &lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container mx-auto py-12"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-4xl font-bold text-gray-900"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                Tailwind CSS Boilerplate (PostCSS + Browsersync + Gulp 4 +
                Imagemin)
            &lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-lg mt-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                Tailwind CSS boilerplate for HTML projects. Bare-bones HTML
                template with Tailwind CSS, PostCSS, Gulp, Imagemin &lt;span class="ni"&gt;&amp;amp;amp;&lt;/span&gt;
                Browsersync.
            &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;If you open this file now in the browser, you won't see Tailwind CSS working. For that, we need to do the following tasks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding Gulp &amp;amp; Browsersync
&lt;/h3&gt;

&lt;p&gt;Next, we need to install the gulp, Browsersync &amp;amp; gulp-postcss plugin.&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;-D&lt;/span&gt; gulp browser-sync gulp-postcss gulp-imagemin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Gulp will help us automate our workflow. Browsersync will help us in reloading the browser automatically after updating files. gulp-postcss will help us in processing our Tailwind CSS.&lt;/p&gt;

&lt;p&gt;Now, let's create the gulpfile. In your project's root folder, create a new file and name it &lt;code&gt;gulpfile.js&lt;/code&gt;. Open this file in the editor and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// gulpfile.js&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;watch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;series&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dest&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gulp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;browserSync&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;browser-sync&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;postcss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gulp-postcss&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;imagemin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gulp-imagemin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Task for compiling our CSS files using PostCSS&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;cssTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cb&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="nf"&gt;src&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./src/*.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// read .css files from ./src/ folder&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;postcss&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="c1"&gt;// compile using postcss&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./assets/css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// paste them in ./assets/css folder&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;browserSync&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="nf"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Task for minifying images&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;imageminTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cb&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="nf"&gt;src&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./assets/images/*&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="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;imagemin&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./assets/images&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nf"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Serve from browserSync server&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;browsersyncServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;browserSync&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;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;baseDir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./&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="p"&gt;});&lt;/span&gt;
    &lt;span class="nf"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;browsersyncReload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;browserSync&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reload&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Watch Files &amp;amp; Reload browser after tasks&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;watchTask&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./**/*.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;browsersyncReload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./src/*.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nf"&gt;series&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cssTask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;browsersyncReload&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Default Gulp Task&lt;/span&gt;
&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;series&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cssTask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;browsersyncServe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;watchTask&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;css&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cssTask&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;images&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;imageminTask&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;We have defined 3 main tasks in this file for Gulp. The first task is for compiling CSS files using PostCSS. We are reading CSS files located in &lt;code&gt;./src&lt;/code&gt; folder, compiling them using PostCSS and then pasting compiled CSS files in &lt;code&gt;./assets/css&lt;/code&gt; folder. &lt;/p&gt;

&lt;p&gt;Another task is created to launch the server from the working directory. As a default Gulp task, we have a series of tasks where we are watching .html &amp;amp; .css files for changes, compiling files &amp;amp; reloading the browser.&lt;/p&gt;

&lt;h3&gt;
  
  
  Defining scripts in package.json
&lt;/h3&gt;

&lt;p&gt;Now, to run those gulp tasks, we will define scripts in our package.json file. We will define 3 scripts here. Check the below code for reference. I'm not adding full package.json as you don't need to change anything else in the file. Just find the &lt;code&gt;scripts&lt;/code&gt; object in the package.json and add the following code:&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="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;package.json&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="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&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;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gulp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NODE_ENV=production gulp css"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"build-images"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gulp images"&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="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&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;p&gt;This step completes our setup. Our project is now ready with the playground.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using our boilerplate
&lt;/h2&gt;

&lt;p&gt;From the root directory of our project, run&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;to start the development server. Now you should be able to see the project running at &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;localhost:3000&lt;/a&gt;. This will watch our .html &amp;amp; .css files for changes. It will compile CSS if needed &amp;amp; reload the browser automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  To build for production
&lt;/h3&gt;

&lt;p&gt;From the root directory of our project, run&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 build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to create the optimized version of the Tailwind CSS file. The compiled file will be saved in the &lt;code&gt;./assets/css/&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;To create optimized version of images stored in &lt;code&gt;./assets/images/&lt;/code&gt; directory, run &lt;code&gt;npm run build-images&lt;/code&gt;. This will replace original images with an optimized version.&lt;/p&gt;

&lt;p&gt;You can find the whole &lt;a href="https://github.com/salttechno/tailwindcss-boilerplate" rel="noopener noreferrer"&gt;Tailwind CSS boilerplate&lt;/a&gt; on GitHub as well. You can clone it, run &lt;code&gt;npm install&lt;/code&gt;, and get started.&lt;/p&gt;

&lt;p&gt;If you find this useful, don't forget to star our GitHub repo. Also, I run a small &lt;a href="https://www.salttechno.ai" rel="noopener noreferrer"&gt;AI development company&lt;/a&gt; in Austin, TX, USA. Do visit our company website.&lt;/p&gt;

&lt;h5&gt;
  
  
  Thank you for reading. I hope this helps you.
&lt;/h5&gt;

</description>
      <category>tailwindcss</category>
      <category>html</category>
      <category>gulp</category>
    </item>
  </channel>
</rss>
