<?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: Asher-ish</title>
    <description>The latest articles on DEV Community by Asher-ish (@asherish).</description>
    <link>https://dev.to/asherish</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%2F3816341%2Ff5ee13eb-777c-45be-9137-200bb733ceca.png</url>
      <title>DEV Community: Asher-ish</title>
      <link>https://dev.to/asherish</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/asherish"/>
    <language>en</language>
    <item>
      <title>Building a Dual-Publishing Blog Platform for Zenn and dev.to</title>
      <dc:creator>Asher-ish</dc:creator>
      <pubDate>Fri, 20 Mar 2026 15:54:19 +0000</pubDate>
      <link>https://dev.to/asherish/building-a-dual-publishing-blog-platform-for-zenn-and-devto-37dh</link>
      <guid>https://dev.to/asherish/building-a-dual-publishing-blog-platform-for-zenn-and-devto-37dh</guid>
      <description>&lt;p&gt;This very article was published to two platforms at once — &lt;a href="https://zenn.dev/" rel="noopener noreferrer"&gt;Zenn&lt;/a&gt; (in Japanese) and dev.to (the English version you're reading now) — from a single &lt;code&gt;git push&lt;/code&gt;. Here's how I built the system that makes it possible.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://zenn.dev/" rel="noopener noreferrer"&gt;Zenn&lt;/a&gt; is a popular tech blogging platform in Japan, similar to dev.to. I write articles in Japanese on Zenn and want the same content available in English on dev.to. But translating by hand is tedious, and the two platforms have subtly different Markdown dialects. So I automated the entire workflow. The source code is public:&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/asherish" rel="noopener noreferrer"&gt;
        asherish
      &lt;/a&gt; / &lt;a href="https://github.com/asherish/blog" rel="noopener noreferrer"&gt;
        blog
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Zenn (JP) + dev.to (EN) dual-publishing blog with bidirectional translation sync
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;blog&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Zenn (Japanese) + dev.to (English) dual-publishing blog platform.&lt;/p&gt;
&lt;p&gt;Write articles in either language, bidirectionally sync translations with Claude Code &lt;code&gt;/sync&lt;/code&gt; skill, and publish to both platforms.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Architecture&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;Write/edit article (JP or EN)
  ↓
/sync                    ← Claude Code translates and syncs bidirectionally
  ↓
articles/ + articles_en/ updated
  ↓
Preview both             ← Zenn (JP) localhost:18000 + dev.to (EN) localhost:13000
  ↓
git push
  ├→ Zenn auto-publish   (GitHub integration)
  └→ GitHub Actions      → validate → dev.to API publishes EN version
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Setup&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Prerequisites&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Node.js 20+&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.anthropic.com/en/docs/claude-code" rel="nofollow noopener noreferrer"&gt;Claude Code&lt;/a&gt; (for translation sync)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/settings/extensions" rel="nofollow"&gt;dev.to API key&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Installation&lt;/h3&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm install&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Environment Variables&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file in the project root:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;DEV_TO_API_KEY=...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;GitHub Secrets&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Add &lt;code&gt;DEV_TO_API_KEY&lt;/code&gt; to your repository's GitHub Secrets for the GitHub Actions workflow.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Zenn Integration&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Link this repository (&lt;code&gt;asherish/blog&lt;/code&gt;, &lt;code&gt;main&lt;/code&gt; branch) at &lt;a href="https://zenn.dev/dashboard/deploys" rel="nofollow noopener noreferrer"&gt;Zenn deploy settings&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;1. Create a new article&lt;/h3&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm run new:article&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;2. Write the article&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Edit the generated file in…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/asherish/blog" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;




&lt;h2&gt;
  
  
  Goals
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Write in Japanese, get the English version auto-generated (and vice versa)&lt;/li&gt;
&lt;li&gt;Convert Markdown syntax differences between Zenn and dev.to automatically&lt;/li&gt;
&lt;li&gt;Publish to both platforms with a single &lt;code&gt;git push&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Preview both platforms locally&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How It Works (The Big Picture)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Write an article (Japanese or English)
  ↓
/sync                    ← Claude Code translates + converts syntax + updates state
  ↓
articles/ + articles_en/ are updated
  ↓
Local preview            ← Zenn (localhost:18000) + dev.to (localhost:13000)
  ↓
git push
  ├→ Zenn auto-publish   (GitHub integration)
  └→ GitHub Actions      → Validate → Publish to dev.to via API
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it: write, &lt;code&gt;/sync&lt;/code&gt;, &lt;code&gt;git push&lt;/code&gt; — published on two platforms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Directory Structure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;blog/
├── .claude/
│   ├── settings.json               &lt;span class="c"&gt;# Auto-allow permissions for sync scripts&lt;/span&gt;
│   └── skills/
│       ├── zenn-syntax.md          &lt;span class="c"&gt;# Zenn syntax reference&lt;/span&gt;
│       ├── devto-syntax.md         &lt;span class="c"&gt;# dev.to syntax reference&lt;/span&gt;
│       └── &lt;span class="nb"&gt;sync&lt;/span&gt;/SKILL.md           &lt;span class="c"&gt;# Bidirectional translation sync skill (/sync)&lt;/span&gt;
├── .github/workflows/
│   ├── publish-to-devto.yml        &lt;span class="c"&gt;# dev.to auto-publish workflow&lt;/span&gt;
│   └── scheduled-publish.yml       &lt;span class="c"&gt;# Scheduled publish cron workflow&lt;/span&gt;
├── articles/                       &lt;span class="c"&gt;# Zenn articles (Japanese)&lt;/span&gt;
├── articles_en/                    &lt;span class="c"&gt;# dev.to articles (English, translated)&lt;/span&gt;
├── books/                          &lt;span class="c"&gt;# Zenn books&lt;/span&gt;
├── scripts/
│   ├── sync-detect.ts              &lt;span class="c"&gt;# Change detection script (JSON output)&lt;/span&gt;
│   ├── sync-apply.ts               &lt;span class="c"&gt;# Post-translation processing script&lt;/span&gt;
│   ├── &lt;span class="nb"&gt;sync&lt;/span&gt;/
│   │   ├── convert.ts              &lt;span class="c"&gt;# Zenn ↔ dev.to syntax conversion&lt;/span&gt;
│   │   └── state.ts                &lt;span class="c"&gt;# Sync state persistence&lt;/span&gt;
│   ├── publish-to-devto.ts         &lt;span class="c"&gt;# dev.to publishing script&lt;/span&gt;
│   ├── process-scheduled.ts        &lt;span class="c"&gt;# Scheduled publish processor&lt;/span&gt;
│   ├── validate-published.ts       &lt;span class="c"&gt;# Pre-publish validation&lt;/span&gt;
│   └── preview-devto.ts            &lt;span class="c"&gt;# dev.to preview server&lt;/span&gt;
├── .sync-state.json                &lt;span class="c"&gt;# Per-article hash tracking&lt;/span&gt;
├── .devto-mapping.json             &lt;span class="c"&gt;# dev.to article ID mapping&lt;/span&gt;
├── package.json
└── tsconfig.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Bidirectional Translation Sync
&lt;/h2&gt;

&lt;p&gt;The heart of this repo is the &lt;code&gt;/sync&lt;/code&gt; command — a custom &lt;a href="https://docs.anthropic.com/en/docs/claude-code" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt; skill that detects changes, translates articles, converts syntax, and updates state in one shot.&lt;/p&gt;

&lt;h3&gt;
  
  
  Change Detection
&lt;/h3&gt;

&lt;p&gt;Every article is SHA-256 hashed and tracked in &lt;code&gt;.sync-state.json&lt;/code&gt;. When you run &lt;code&gt;/sync&lt;/code&gt;, the script compares current hashes against stored ones to figure out what changed:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;State&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Only Japanese exists&lt;/td&gt;
&lt;td&gt;Full translation JP → EN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Only English exists&lt;/td&gt;
&lt;td&gt;Full translation EN → JP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Japanese was modified&lt;/td&gt;
&lt;td&gt;Diff sync JP → EN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;English was modified&lt;/td&gt;
&lt;td&gt;Diff sync EN → JP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Both were modified&lt;/td&gt;
&lt;td&gt;Conflict → resolve with &lt;code&gt;--prefer ja&lt;/code&gt; or &lt;code&gt;--prefer en&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No changes&lt;/td&gt;
&lt;td&gt;Skip&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  The Three-Step Pipeline
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Step 1 — Detect&lt;/strong&gt; (&lt;code&gt;sync-detect.ts&lt;/code&gt;): Compares hashes and outputs which articles need translation (and in which direction) as JSON.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2 — Translate&lt;/strong&gt; (Claude Code): Reads the source article and writes the translated body to the target file. Code blocks, inline code, URLs, and command names are preserved as-is. Platform-specific syntax (&lt;code&gt;:::message&lt;/code&gt;, &lt;code&gt;$$&lt;/code&gt;, etc.) is also left untouched — syntax conversion happens in the next step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3 — Post-process&lt;/strong&gt; (&lt;code&gt;sync-apply.ts&lt;/code&gt;): Converts Zenn ↔ dev.to syntax via regex, generates the target-side frontmatter, and updates &lt;code&gt;.sync-state.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Separating translation from syntax conversion keeps the translation prompt clean and lets regex handle the mechanical conversions reliably.&lt;/p&gt;

&lt;h3&gt;
  
  
  Usage
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/sync                    &lt;span class="c"&gt;# Sync all articles&lt;/span&gt;
/sync my-article         &lt;span class="c"&gt;# Sync a specific article only&lt;/span&gt;
/sync &lt;span class="nt"&gt;--prefer&lt;/span&gt; ja        &lt;span class="c"&gt;# Resolve conflicts — Japanese wins&lt;/span&gt;
/sync &lt;span class="nt"&gt;--prefer&lt;/span&gt; en        &lt;span class="c"&gt;# Resolve conflicts — English wins&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also run change detection alone:&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;sync&lt;/span&gt;                    &lt;span class="c"&gt;# All articles (JSON output)&lt;/span&gt;
npm run &lt;span class="nb"&gt;sync&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; my-article      &lt;span class="c"&gt;# Single article&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why Claude Code Instead of the Claude API?
&lt;/h3&gt;

&lt;p&gt;The first version called the Claude API directly from TypeScript (&lt;code&gt;sync.ts&lt;/code&gt; + &lt;code&gt;api.ts&lt;/code&gt;). I switched to a Claude Code skill because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No API key needed&lt;/strong&gt; — Claude Code handles the translation itself; no &lt;code&gt;ANTHROPIC_API_KEY&lt;/code&gt; in &lt;code&gt;.env&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better quality&lt;/strong&gt; — full article context in every translation, no prompt-length workarounds&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interactive debugging&lt;/strong&gt; — review and fix translations on the spot, re-run with &lt;code&gt;/sync&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parallel execution&lt;/strong&gt; — Claude Code's background agents can translate multiple articles at once&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Zenn ↔ dev.to Syntax Conversion
&lt;/h2&gt;

&lt;p&gt;Both platforms use Markdown, but each has its own extensions. The converter handles these automatically — here's what it translates:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Zenn&lt;/th&gt;
&lt;th&gt;dev.to&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Info box&lt;/td&gt;
&lt;td&gt;&lt;code&gt;:::message ... :::&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;gt; ℹ️ ...&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Warning box&lt;/td&gt;
&lt;td&gt;&lt;code&gt;:::message alert ... :::&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;gt; ⚠️ ...&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Accordion&lt;/td&gt;
&lt;td&gt;&lt;code&gt;:::details Title ... :::&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{% details Title %} ... {% enddetails %}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Block math&lt;/td&gt;
&lt;td&gt;&lt;code&gt;$$ ... $$&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{% katex %} ... {% endkatex %}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inline math&lt;/td&gt;
&lt;td&gt;&lt;code&gt;$...$&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{% katex inline %}...{% endkatex %}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code filename&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&lt;/code&gt;&lt;code&gt;js:app.js&lt;/code&gt;`&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&lt;/code&gt; &lt;code&gt;&lt;/code&gt;&lt;code&gt;js&lt;/code&gt;&lt;code&gt; + &lt;/code&gt;// app.js` comment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Image width&lt;/td&gt;
&lt;td&gt;&lt;code&gt;![alt](url =500x)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;img src="url" alt="alt" width="500"&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Footnotes&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[^1]: text&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;**Notes:** 1. text&lt;/code&gt; section&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All conversions are regex-based and work in both directions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Frontmatter
&lt;/h3&gt;

&lt;p&gt;Frontmatter differs too:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Zenn&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;記事タイトル"&lt;/span&gt;
&lt;span class="na"&gt;emoji&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;🐙"&lt;/span&gt;
&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tech"&lt;/span&gt;
&lt;span class="na"&gt;topics&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;topic1"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;topic2"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;published&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="c1"&gt;# dev.to&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Article&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Title"&lt;/span&gt;
&lt;span class="na"&gt;published&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;topic1, topic2&lt;/span&gt;
&lt;span class="na"&gt;canonical_url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://zenn.dev/asherish/articles/slug&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;code&gt;canonical_url&lt;/code&gt; pointing to the Zenn article is added automatically to avoid SEO duplicate-content issues. dev.to limits tags to 4, so only the first 4 Zenn topics are carried over.&lt;/p&gt;

&lt;h2&gt;
  
  
  Local Preview
&lt;/h2&gt;

&lt;p&gt;Both platforms can be previewed locally:&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 preview        &lt;span class="c"&gt;# Zenn  → localhost:18000&lt;/span&gt;
npm run preview:devto  &lt;span class="c"&gt;# dev.to → localhost:13000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Zenn preview uses the official Zenn CLI. The dev.to preview is a lightweight HTTP server that renders &lt;code&gt;articles_en/&lt;/code&gt; Markdown with &lt;code&gt;marked&lt;/code&gt; in a dev.to-like layout. Ports are offset by 10,000 from the usual 8000/3000 to avoid clashing with Next.js or Express dev servers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Publishing with GitHub Actions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Zenn&lt;/strong&gt; has no publish API — it polls your linked GitHub repo and imports &lt;code&gt;articles/&lt;/code&gt; automatically. Just &lt;code&gt;git push&lt;/code&gt; and you're done.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;dev.to&lt;/strong&gt; has a REST API, so a GitHub Actions workflow handles it. It triggers on pushes to &lt;code&gt;main&lt;/code&gt; that touch &lt;code&gt;articles_en/&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;articles_en/**'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The workflow runs three steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Validate&lt;/strong&gt; — Checks that &lt;code&gt;published&lt;/code&gt; status matches between the JP and EN articles. A mismatch (one side &lt;code&gt;true&lt;/code&gt;, the other &lt;code&gt;false&lt;/code&gt;) would cause an accidental publish, so the workflow stops.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Publish&lt;/strong&gt; — Calls &lt;code&gt;POST /api/articles&lt;/code&gt; (first time) or &lt;code&gt;PUT /api/articles/{id}&lt;/code&gt; (updates) on the dev.to API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Save mapping&lt;/strong&gt; — Commits the slug → dev.to article ID mapping to &lt;code&gt;.devto-mapping.json&lt;/code&gt; so future runs can update the same article.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Scheduled Publishing
&lt;/h2&gt;

&lt;p&gt;Want to publish on a specific date? Add &lt;code&gt;scheduled_publish_date&lt;/code&gt; to both articles' frontmatter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;published&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="na"&gt;scheduled_publish_date&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2026-03-15"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A GitHub Actions cron runs daily at 00:05 JST. When the date arrives, it flips &lt;code&gt;published&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt;, publishes the EN version via the dev.to API, and commits. Zenn picks up the change automatically.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;scheduled-publish.yml (daily cron at 00:05 JST)
  ↓
process-scheduled.ts
  ├─ scheduled date ≤ today → set published: true
  ↓
publish-to-devto.ts
  ├─ publish English version via dev.to API
  ↓
commit &amp;amp; push
  └→ Zenn auto-publish (GitHub integration)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check scheduling status locally with &lt;code&gt;npm run schedule:check&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Not Zenn's Built-in Scheduling?
&lt;/h3&gt;

&lt;p&gt;Zenn supports scheduling via &lt;code&gt;published: true&lt;/code&gt; + &lt;code&gt;published_at&lt;/code&gt;, but it requires &lt;code&gt;published: true&lt;/code&gt; upfront. dev.to has no equivalent — &lt;code&gt;published: true&lt;/code&gt; goes live immediately. Using Zenn's native scheduling would leave the two platforms out of sync, which trips the validation script. Instead, a custom &lt;code&gt;scheduled_publish_date&lt;/code&gt; field keeps both sides in sync, and the cron publishes them simultaneously.&lt;/p&gt;

&lt;h2&gt;
  
  
  Claude Code Skills
&lt;/h2&gt;

&lt;p&gt;The repo ships three Claude Code skill files:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Skill&lt;/th&gt;
&lt;th&gt;Trigger&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sync&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;/sync&lt;/code&gt; command&lt;/td&gt;
&lt;td&gt;Bidirectional translation sync&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;zenn-syntax&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Editing &lt;code&gt;articles/&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Loads Zenn syntax reference&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;devto-syntax&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Editing &lt;code&gt;articles_en/&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Loads dev.to syntax reference&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The syntax skills auto-load when you're editing in the corresponding directory, so Claude Code always knows which platform's Markdown to use. Permissions for script execution and file I/O are pre-approved in &lt;code&gt;.claude/settings.json&lt;/code&gt; so background agents can translate in parallel without blocking on approval prompts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;My daily workflow now looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write an article in Japanese in &lt;code&gt;articles/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;/sync&lt;/code&gt; to generate the English version&lt;/li&gt;
&lt;li&gt;Preview with &lt;code&gt;npm run preview&lt;/code&gt; / &lt;code&gt;npm run preview:devto&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git push&lt;/code&gt; — published on both Zenn and dev.to&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Since Claude Code handles the translation directly, there's no API key to manage, and I can review and tweak translations on the spot. The diff sync mechanism means manual edits to translations survive the next sync. The result: I just write in Japanese and everything else is automated.&lt;/p&gt;

</description>
      <category>zenn</category>
      <category>devto</category>
      <category>claudecode</category>
      <category>githubactions</category>
    </item>
    <item>
      <title>Installing NVIDIA Drivers Without CUDA</title>
      <dc:creator>Asher-ish</dc:creator>
      <pubDate>Thu, 19 Mar 2026 16:03:33 +0000</pubDate>
      <link>https://dev.to/asherish/installing-nvidia-drivers-without-cuda-1bgk</link>
      <guid>https://dev.to/asherish/installing-nvidia-drivers-without-cuda-1bgk</guid>
      <description>&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;In AI model development environments, different projects and programs often require different versions of CUDA. For example, one project might need CUDA 11.8 while another requires CUDA 12.2. In such situations, installing and managing multiple CUDA versions directly on your local environment can lead to version conflicts.&lt;/p&gt;

&lt;p&gt;Furthermore, when sharing development environments across a team, configurations that depend on the local environment make it difficult to ensure reproducibility. If each team member uses a different CUDA version, errors due to environmental differences become more likely.&lt;/p&gt;

&lt;p&gt;Therefore, CUDA should be installed inside containers rather than on the local environment. By using containers, you can flexibly switch between the CUDA versions needed for each project without affecting the local environment. Additionally, sharing containers across the team enables a unified development environment.&lt;/p&gt;

&lt;p&gt;This article aims to install only the NVIDIA driver on the local environment without installing CUDA.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check the Version to Install
&lt;/h2&gt;

&lt;p&gt;First, use the following site to check which version to install. By selecting your GPU product name and OS, you can find the appropriate NVIDIA driver version.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.nvidia.com/ja-jp/drivers/" rel="noopener noreferrer"&gt;https://www.nvidia.com/ja-jp/drivers/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you don't know your GPU model, you can check it with the following command:&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;sudo &lt;/span&gt;lshw &lt;span class="nt"&gt;-C&lt;/span&gt; display
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How to Install the NVIDIA Driver Without CUDA
&lt;/h2&gt;

&lt;p&gt;There are two main methods for installing the NVIDIA driver:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;NVIDIA repository + &lt;code&gt;cuda-drivers&lt;/code&gt;&lt;/strong&gt;: Installs from NVIDIA's repository. Provides the latest drivers. The repository configuration can be reused if you install CUDA in the future. See Reference: Installation via the NVIDIA Repository for details.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ubuntu repository + &lt;code&gt;nvidia-driver-XXX&lt;/code&gt;&lt;/strong&gt;: Installs drivers that have been tested and packaged by Ubuntu. You can check the recommended version with the &lt;code&gt;ubuntu-drivers devices&lt;/code&gt; command, and the procedure is simpler.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article explains the installation steps using the latter approach with the Ubuntu repository.&lt;/p&gt;

&lt;h3&gt;
  
  
  About Secure Boot
&lt;/h3&gt;

&lt;p&gt;Secure Boot is a BIOS/UEFI security feature that only allows trusted, signed software to run during PC startup. If the NVIDIA driver's kernel module is not signed, this feature can prevent it from working. Therefore, to install the NVIDIA driver successfully, you need to either disable Secure Boot or register a MOK (Machine-Owner Key).&lt;/p&gt;

&lt;h4&gt;
  
  
  Option 1: Disable Secure Boot in BIOS
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Immediately after powering on, repeatedly press the designated key to enter BIOS.

&lt;ul&gt;
&lt;li&gt;DELL: F2 or DEL&lt;/li&gt;
&lt;li&gt;HP: ESC (then F10) or F2&lt;/li&gt;
&lt;li&gt;ASUS: DEL or F2&lt;/li&gt;
&lt;li&gt;Acer: F2 or DEL&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Navigate to the Secure Boot settings screen.
It is usually found under one of the following tabs:

&lt;ul&gt;
&lt;li&gt;Boot&lt;/li&gt;
&lt;li&gt;Security&lt;/li&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;li&gt;Advanced&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Disable Secure Boot.

&lt;ul&gt;
&lt;li&gt;Set the "Secure Boot" option to "Disabled".&lt;/li&gt;
&lt;li&gt;If you cannot disable it, try changing the Secure Boot mode to "Custom Mode" first.&lt;/li&gt;
&lt;li&gt;In some cases, changing OS Type from "Windows UEFI mode" to "Other OS" is sufficient.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Configure "CSM" or "Legacy Boot" if necessary.

&lt;ul&gt;
&lt;li&gt;On some systems, you may need to enable "CSM (Compatibility Support Module)" or "Legacy Boot" when disabling Secure Boot.&lt;/li&gt;
&lt;li&gt;To do this, set "CSM" or "Legacy Boot" to "Enabled" in the "Boot" tab.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Save changes and restart.

&lt;ul&gt;
&lt;li&gt;After making changes, select "Save and Exit".&lt;/li&gt;
&lt;li&gt;On some BIOS, you can save and exit with the F10 key.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Verify that Secure Boot has been disabled.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   dmesg | &lt;span class="nb"&gt;grep &lt;/span&gt;Secure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Option 2: Register a MOK (Machine-Owner Key)
&lt;/h4&gt;

&lt;p&gt;If you want to use the NVIDIA driver with Secure Boot enabled, you will be prompted to register a MOK during driver installation. Set a password when prompted during installation. After rebooting, the "Enroll MOK" menu will appear — enter the password you set to register the MOK.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ If you do not select "Enroll MOK" during reboot, Ubuntu will still boot, but the NVIDIA driver will not work correctly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Disable nouveau
&lt;/h3&gt;

&lt;p&gt;When installing NVIDIA drivers on a Linux system, an open-source driver called nouveau may be enabled by default. When nouveau is active, it occupies the GPU, which can interfere with the installation and operation of the NVIDIA driver. Therefore, to install the NVIDIA driver correctly, you need to disable nouveau to release the GPU.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check if nouveau is enabled. You can paste the output into ChatGPT to verify whether it is enabled.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   lsmod | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; nouveau
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Run &lt;code&gt;sudo vi /etc/modprobe.d/blacklist-nvidia-nouveau.conf&lt;/code&gt; and add the following configuration to disable nouveau.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   blacklist nouveau
   options nouveau modset=0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Apply the configuration to disable nouveau.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;sudo &lt;/span&gt;update-initramfs &lt;span class="nt"&gt;-u&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;⚠️ Do not reboot. If you reboot without installing the NVIDIA driver, you may experience display issues.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Install the NVIDIA Driver
&lt;/h3&gt;

&lt;p&gt;Finally, it's time to install the NVIDIA driver. Once this is complete, you've achieved the goal.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Remove any previously installed NVIDIA drivers or CUDA.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;sudo &lt;/span&gt;apt purge &lt;span class="s2"&gt;"nvidia-*"&lt;/span&gt;
   &lt;span class="nb"&gt;sudo &lt;/span&gt;apt autoremove
   &lt;span class="nb"&gt;sudo &lt;/span&gt;apt autoclean
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Update the package list to the latest state.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
   &lt;span class="nb"&gt;sudo &lt;/span&gt;apt upgrade &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Check the version to install on the &lt;a href="https://www.nvidia.com/ja-jp/drivers/" rel="noopener noreferrer"&gt;NVIDIA official driver page&lt;/a&gt; as described in Check the Version to Install earlier in this article.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ To determine which version to install, you need to know your GPU model. You can check it with &lt;code&gt;sudo lshw -C display&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As a side note, you can also check the list of compatible drivers and recommended versions using the &lt;code&gt;ubuntu-drivers devices&lt;/code&gt; command. Running this command will often show the open-source version of the driver recommended on &lt;a href="https://www.nvidia.com/ja-jp/drivers/" rel="noopener noreferrer"&gt;the page above&lt;/a&gt; marked as &lt;code&gt;recommended&lt;/code&gt;. In fact, NVIDIA's developer page also recommends using the open-source kernel modules for Turing and later architectures (Turing, Ampere, Ada Lovelace, Hopper), and starting from the R560 driver series, the open-source version is the default installation target (&lt;a href="https://developer.nvidia.com/blog/nvidia-transitions-fully-towards-open-source-gpu-kernel-modules/" rel="noopener noreferrer"&gt;reference&lt;/a&gt;). However, even the recommended version may not always work correctly.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install the appropriate version of the driver (the following command is for version &lt;code&gt;535&lt;/code&gt;).
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; nvidia-driver-535
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Verify that the driver was installed successfully. If GPU information is displayed, the installation was successful.
&lt;/li&gt;
&lt;/ol&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Notes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The procedures in this article are intended for Ubuntu environments.&lt;/li&gt;
&lt;li&gt;NVIDIA's official documentation describes different installation methods.
&lt;a href="https://docs.nvidia.com/datacenter/tesla/driver-installation-guide/#ubuntu" rel="noopener noreferrer"&gt;https://docs.nvidia.com/datacenter/tesla/driver-installation-guide/#ubuntu&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Reference: Installation via the NVIDIA Repository
&lt;/h2&gt;

&lt;p&gt;This article introduced the method using Ubuntu's repository, but you can also install drivers using NVIDIA's repository. Here, we organize the information from the CUDA Installation Guide as a reference.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation Instructions Are in the CUDA Installation Guide
&lt;/h3&gt;

&lt;p&gt;The NVIDIA driver installation instructions are documented in the CUDA Installation Guide. This is a good page to come back to when you get stuck. However, since this page is designed to support CUDA installation, you'll need to read selectively to install only the NVIDIA driver.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html" rel="noopener noreferrer"&gt;https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Section 3. Pre-installation Actions describes what needs to be done before installation. In particular, we'll cover the following subsections:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;3.4. Choose an Installation Method&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;3.5. Download the NVIDIA CUDA Toolkit&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ The CUDA Quick Start Guide also describes CUDA installation procedures, but it only covers full CUDA installation and does not describe how to install the NVIDIA driver without CUDA.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.nvidia.com/cuda/cuda-quick-start-guide/index.html#ubuntu" rel="noopener noreferrer"&gt;https://docs.nvidia.com/cuda/cuda-quick-start-guide/index.html#ubuntu&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Two Types: distribution-specific package and runfile
&lt;/h3&gt;

&lt;p&gt;Section &lt;strong&gt;3.4. Choose an Installation Method&lt;/strong&gt; of the CUDA Installation Guide explains that there are two installation methods.&lt;/p&gt;

&lt;p&gt;Let's look at what the installation guide says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The CUDA Toolkit can be installed using either of two different installation mechanisms: distribution-specific packages (RPM and Deb packages), or a distribution-independent package (runfile packages).&lt;/p&gt;

&lt;p&gt;The distribution-independent package has the advantage of working across a wider set of Linux distributions, but does not update the distribution's native package management system. The distribution-specific packages interface with the distribution's native package management system. It is recommended to use the distribution-specific packages, where possible.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As described above, there are two installation methods: distribution-specific packages (deb/rpm packages) and distribution-independent packages (runfile). The guide recommends the former.&lt;/p&gt;

&lt;p&gt;Note that the runfile also has &lt;code&gt;--driver&lt;/code&gt; and &lt;code&gt;--toolkit&lt;/code&gt; flags documented, which may allow installing only the driver or only the toolkit separately. However, the following sections assume distribution-specific packages (deb) as recommended by the guide.&lt;/p&gt;

&lt;h3&gt;
  
  
  Downloading the NVIDIA Driver
&lt;/h3&gt;

&lt;p&gt;Section &lt;strong&gt;3.5. Download the NVIDIA CUDA Toolkit&lt;/strong&gt; of the CUDA Installation Guide explains the following:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The NVIDIA CUDA Toolkit is available at &lt;a href="https://developer.nvidia.com/cuda-downloads" rel="noopener noreferrer"&gt;https://developer.nvidia.com/cuda-downloads&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Choose the platform you are using and download the NVIDIA CUDA Toolkit.&lt;/p&gt;

&lt;p&gt;The CUDA Toolkit contains the tools needed to create, build and run a CUDA application as well as libraries, header files, and other resources.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When you open the link above and select your environment, the installation methods for both CUDA and the NVIDIA driver are displayed. However, if you select the runfile option, the NVIDIA driver installation method is not shown. You need to select deb.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.nvidia.com/cuda-downloads" rel="noopener noreferrer"&gt;https://developer.nvidia.com/cuda-downloads&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For example, if you select Linux, x86_64, Ubuntu 22.04, deb (network), the following is shown as the NVIDIA driver installation step:&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;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; cuda-drivers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  local and network Methods
&lt;/h3&gt;

&lt;p&gt;The deb package installation method is further divided into two types: local and network.&lt;/p&gt;

&lt;p&gt;Section 4.8 of the CUDA Installation Guide describes the installation method for Ubuntu.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#ubuntu" rel="noopener noreferrer"&gt;https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#ubuntu&lt;/a&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="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;linux-headers-&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-key del 7fa2af80

&lt;span class="c"&gt;# Choose an installation method: local repo or network repo.&lt;/span&gt;

&lt;span class="c"&gt;# local&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;dpkg &lt;span class="nt"&gt;-i&lt;/span&gt; cuda-repo-&amp;lt;distro&amp;gt;_&amp;lt;version&amp;gt;_&amp;lt;architecture&amp;gt;.deb
&lt;span class="nb"&gt;sudo cp&lt;/span&gt; /var/cuda-repo-&amp;lt;distro&amp;gt;-X-Y-local/cuda-&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="nt"&gt;-keyring&lt;/span&gt;.gpg /usr/share/keyrings/
wget https://developer.download.nvidia.com/compute/cuda/repos/&amp;lt;distro&amp;gt;/x86_64/cuda-&amp;lt;distro&amp;gt;.pin
&lt;span class="nb"&gt;sudo mv &lt;/span&gt;cuda-&amp;lt;distro&amp;gt;.pin /etc/apt/preferences.d/cuda-repository-pin-600

&lt;span class="c"&gt;# network&lt;/span&gt;
wget https://developer.download.nvidia.com/compute/cuda/repos/&lt;span class="o"&gt;{&lt;/span&gt;% katex inline %&lt;span class="o"&gt;}&lt;/span&gt;distro/&lt;span class="o"&gt;{&lt;/span&gt;% endkatex %&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="nb"&gt;arch&lt;/span&gt;/cuda-keyring_1.1-1_all.deb
&lt;span class="nb"&gt;sudo &lt;/span&gt;dpkg &lt;span class="nt"&gt;-i&lt;/span&gt; cuda-keyring_1.1-1_all.deb
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;cuda-drivers-&amp;lt;branch&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The developer site also displays the necessary commands when you select the OS and installer type. The specific commands vary depending on the CUDA version, so please select your environment on the following page to check:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.nvidia.com/cuda-downloads" rel="noopener noreferrer"&gt;https://developer.nvidia.com/cuda-downloads&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For example, if you select Linux, x86_64, Ubuntu 22.04, deb (local), the repository setup commands are displayed. After setting up the repository, you can install only the NVIDIA driver without CUDA by installing &lt;code&gt;cuda-drivers&lt;/code&gt; instead of &lt;code&gt;cuda-toolkit&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;# cuda-toolkit をインストールすると CUDA がインストールされてしまう&lt;/span&gt;
&lt;span class="c"&gt;# sudo apt-get -y install cuda-toolkit-&amp;lt;version&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;# cuda-drivers をインストールすると CUDA なしで NVIDIA ドライバーのみをインストールできる&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nb"&gt;install &lt;/span&gt;cuda-drivers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>nvidia</category>
      <category>cuda</category>
      <category>ubuntu</category>
      <category>linux</category>
    </item>
    <item>
      <title>Fixing Ubuntu Desktop Freezing at the Login Screen</title>
      <dc:creator>Asher-ish</dc:creator>
      <pubDate>Wed, 11 Mar 2026 15:58:14 +0000</pubDate>
      <link>https://dev.to/asherish/fixing-ubuntu-desktop-freezing-at-the-login-screen-4j3d</link>
      <guid>https://dev.to/asherish/fixing-ubuntu-desktop-freezing-at-the-login-screen-4j3d</guid>
      <description>&lt;p&gt;When installing Ubuntu Desktop, the system may freeze at login if the default graphics settings are incompatible with the hardware. This article explains how to resolve this issue.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Ubuntu Desktop?
&lt;/h2&gt;

&lt;p&gt;Ubuntu comes in two varieties: "Ubuntu Server" for server use, and "Ubuntu Desktop" for personal and office use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ubuntu Server&lt;/strong&gt; is designed primarily for server operations and is intended to be operated via command line (CUI). It does not include a GUI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ubuntu Desktop&lt;/strong&gt; is designed for personal and office use, with an intuitive GUI included as standard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why It Freezes
&lt;/h2&gt;

&lt;p&gt;Normally, the kernel initializes the framebuffer (the display area using the GPU) during boot and sets the optimal resolution. However, when this operation fails, the following problems can occur:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The screen goes black&lt;/li&gt;
&lt;li&gt;The boot process freezes&lt;/li&gt;
&lt;li&gt;The login screen doesn't appear&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The main cause of this failure is that the open-source driver is not compatible with the installed GPU.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: Open-source drivers are the drivers installed by default on Ubuntu, such as &lt;code&gt;nouveau&lt;/code&gt; (for NVIDIA), &lt;code&gt;amdgpu&lt;/code&gt; (for AMD), and &lt;code&gt;modesetting&lt;/code&gt; (a generic driver).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For example, the open-source driver may fail to initialize the framebuffer for the latest NVIDIA GPUs, causing a freeze at login. BIOS/UEFI settings or specific hardware configurations (e.g., multi-GPU environments) can also be the cause.&lt;/p&gt;

&lt;p&gt;Installing a proprietary driver is required for NVIDIA GPUs to set the optimal resolution, but you can't install the proprietary driver without being able to log in first.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Log In
&lt;/h2&gt;

&lt;p&gt;Using &lt;code&gt;nomodeset&lt;/code&gt; disables automatic initialization and runs in low-resolution mode, allowing you to use the GUI environment. Note that this is a temporary fix — you'll need to install the proprietary driver as a permanent solution.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Display the GRUB menu at boot (press the Shift key repeatedly)&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;e&lt;/code&gt; before selecting "Ubuntu"&lt;/li&gt;
&lt;li&gt;Change &lt;code&gt;quiet splash&lt;/code&gt; to &lt;code&gt;quiet splash nomodeset&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Boot with Ctrl + X&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This starts the GUI in low-resolution mode, allowing you to log in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install the Proprietary Driver
&lt;/h2&gt;

&lt;p&gt;After logging in, install the proprietary driver to display the screen at the proper resolution. The following example is for NVIDIA GPUs.&lt;/p&gt;

&lt;p&gt;Check the recommended driver:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ubuntu-drivers devices
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install the recommended driver:&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;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;nvidia-driver-xxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;The officially provided driver from the repository is recommended, but if needed, download and install the latest driver from the &lt;a href="https://www.nvidia.com/" rel="noopener noreferrer"&gt;NVIDIA official website&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Remove nomodeset
&lt;/h2&gt;

&lt;p&gt;After installing the proprietary driver, remove &lt;code&gt;nomodeset&lt;/code&gt; from the GRUB configuration.&lt;/p&gt;

&lt;p&gt;Edit the GRUB configuration (e.g., using &lt;code&gt;nano&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="nb"&gt;sudo &lt;/span&gt;nano /etc/default/grub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Find the following line:&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;GRUB_CMDLINE_LINUX_DEFAULT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"quiet splash nomodeset"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change it to:&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;GRUB_CMDLINE_LINUX_DEFAULT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"quiet splash"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the settings and update GRUB:&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;sudo &lt;/span&gt;update-grub
&lt;span class="nb"&gt;sudo &lt;/span&gt;reboot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After rebooting, verify that the proprietary driver is working correctly with the following command:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Note: For AMD or Intel GPUs
&lt;/h2&gt;

&lt;p&gt;Even with AMD or Intel GPUs, similar issues can occur due to open-source drivers.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For AMD: Check if the &lt;code&gt;amdgpu&lt;/code&gt; driver is applied, and install the proprietary driver if necessary.&lt;/li&gt;
&lt;li&gt;For Intel: Check if the &lt;code&gt;i915&lt;/code&gt; driver is applied.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the specific problem is not resolved, refer to official documentation or support forums.&lt;/p&gt;

</description>
      <category>ubuntu</category>
      <category>linux</category>
      <category>nvidia</category>
      <category>gpu</category>
    </item>
    <item>
      <title>Publish Pipeline Test Article</title>
      <dc:creator>Asher-ish</dc:creator>
      <pubDate>Tue, 10 Mar 2026 08:28:29 +0000</pubDate>
      <link>https://dev.to/asherish/publish-pipeline-test-article-4kf4</link>
      <guid>https://dev.to/asherish/publish-pipeline-test-article-4kf4</guid>
      <description>&lt;p&gt;This is a test article. It will be deleted after confirming the publish pipeline works.&lt;/p&gt;

</description>
      <category>test</category>
    </item>
  </channel>
</rss>
