<?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: Kushal</title>
    <description>The latest articles on DEV Community by Kushal (@kushal).</description>
    <link>https://dev.to/kushal</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F279465%2F1fd88e6a-9790-458c-b956-96d24dd0c4b3.png</url>
      <title>DEV Community: Kushal</title>
      <link>https://dev.to/kushal</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kushal"/>
    <language>en</language>
    <item>
      <title>Announcing Open Knowledge Compiler: a compiler for the Open Knowledge Format</title>
      <dc:creator>Kushal</dc:creator>
      <pubDate>Thu, 06 Aug 2026 13:50:23 +0000</pubDate>
      <link>https://dev.to/kushal/announcing-open-knowledge-compiler-a-compiler-for-the-open-knowledge-format-hje</link>
      <guid>https://dev.to/kushal/announcing-open-knowledge-compiler-a-compiler-for-the-open-knowledge-format-hje</guid>
      <description>&lt;h3&gt;
  
  
  Raw engineering artifacts go in. A living, queryable, agent-readable knowledge base comes out.
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; — &lt;a href="https://github.com/kushal-omnius/open-knowledge-compiler" rel="noopener noreferrer"&gt;Open Knowledge Compiler&lt;/a&gt; (&lt;code&gt;open-knowledge-compiler&lt;/code&gt;, Apache-2.0) is a new open-source tool that continuously compiles a Git repository — its code, pull requests, and optionally Jira — into a knowledge base that is simultaneously a browsable wiki for humans and a structured, queryable graph for AI agents. The output is a conformant &lt;a href="https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md" rel="noopener noreferrer"&gt;OKF&lt;/a&gt; (Open Knowledge Format) bundle, checked by the tool's own conformance validator, not just claimed. This post explains what OKF is, what Knowledge Compiler actually does today, and where the two genuinely different roles — &lt;em&gt;producer&lt;/em&gt; and &lt;em&gt;consumer&lt;/em&gt; — split apart.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The problem this is solving
&lt;/h2&gt;

&lt;p&gt;If you've tried to wire an AI coding agent into a real codebase, you've hit the same wall from three different directions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The agent can read code, but it can't tell you &lt;em&gt;why&lt;/em&gt; a piece of code exists — which business rule it enforces, which Jira ticket motivated the change, whether it's actually tested.&lt;/li&gt;
&lt;li&gt;Documentation about "what this system does" lives in five places — a wiki nobody updates, a Confluence page from eighteen months ago, tribal knowledge in someone's head, and scattered code comments — and none of them are current.&lt;/li&gt;
&lt;li&gt;Every new agent, every new tool, every new integration re-solves the same problem: &lt;em&gt;how do I assemble enough context about this codebase to be useful?&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is exactly the gap the &lt;strong&gt;Open Knowledge Format (OKF)&lt;/strong&gt; was designed to close, and exactly the gap Open Knowledge Compiler exists to fill &lt;em&gt;automatically&lt;/em&gt;, rather than asking a human to maintain it by hand.&lt;/p&gt;




&lt;h2&gt;
  
  
  What OKF actually is
&lt;/h2&gt;

&lt;p&gt;Open Knowledge Format is an open specification — not a product, not a vendor SDK — published by Google Cloud's Data Analytics and Data Cloud teams (&lt;a href="https://cloud.google.com/blog/products/data-analytics/how-the-open-knowledge-format-can-improve-data-sharing" rel="noopener noreferrer"&gt;Sam McVeety&lt;/a&gt; and Amir Hormati), building on an idea Andrej Karpathy sketched in an &lt;a href="https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f" rel="noopener noreferrer"&gt;LLM-wiki gist&lt;/a&gt;. It formalizes a pattern a lot of people were already converging on independently — Obsidian vaults, &lt;code&gt;AGENTS.md&lt;/code&gt;/&lt;code&gt;CLAUDE.md&lt;/code&gt; files, "metadata as code" repos — into something interoperable.&lt;/p&gt;

&lt;p&gt;The spec (currently &lt;strong&gt;v0.2&lt;/strong&gt;) is deliberately small. An OKF &lt;strong&gt;bundle&lt;/strong&gt; is a directory tree of Markdown files. Each file is a &lt;strong&gt;concept&lt;/strong&gt; — a table, a metric, a component, a business rule, whatever your domain needs — with YAML frontmatter on top:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
type: Component
title: Billing rules
description: Discount calculation and eligibility checks.
tags: [billing, revenue]
generated:
  by: process:some-producer/1.0
  at: 2026-08-05T14:31:43+00:00
---
# Billing rules

Applies the discount cap and eligibility checks before a claim is saved.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only one field is universally required: &lt;code&gt;type&lt;/code&gt;. Everything else — &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;description&lt;/code&gt;, &lt;code&gt;resource&lt;/code&gt;, &lt;code&gt;tags&lt;/code&gt;, the provenance-oriented &lt;code&gt;sources&lt;/code&gt;/&lt;code&gt;generated&lt;/code&gt;/&lt;code&gt;verified&lt;/code&gt; fields, the lifecycle &lt;code&gt;status&lt;/code&gt;/&lt;code&gt;stale_after&lt;/code&gt; fields — is optional or recommended, not mandated. Two filenames are reserved with exact structure: &lt;code&gt;index.md&lt;/code&gt; (a directory listing, no general frontmatter) and &lt;code&gt;log.md&lt;/code&gt; (a date-grouped, prose changelog, also no frontmatter). Everything else about the file's shape is designed to be tolerant: unknown types, broken links, missing optional fields — none of it is grounds for a consumer to reject a bundle.&lt;/p&gt;

&lt;p&gt;That minimalism is the point. OKF's own design principles state it plainly: &lt;strong&gt;producers and consumers are independent&lt;/strong&gt;. Anyone can write a producer (something that emits OKF bundles) or a consumer (something that reads them — a viewer, a search index, an agent) without coordinating with anyone else, as long as both sides honor the spec.&lt;/p&gt;

&lt;p&gt;Google shipped a reference producer alongside the spec: an agent that walks BigQuery datasets and drafts OKF concept documents for each table, plus a static HTML bundle visualizer. Both are useful demonstrations. Neither is aimed at software engineering repositories, and neither continuously re-syncs — they're one-shot generation tools.&lt;/p&gt;

&lt;p&gt;That's the gap Open Knowledge Compiler fills.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Open Knowledge Compiler is
&lt;/h2&gt;

&lt;p&gt;Open Knowledge Compiler (package name &lt;code&gt;open-knowledge-compiler&lt;/code&gt;, CLI command &lt;code&gt;kc&lt;/code&gt;) is an independent, third-party &lt;strong&gt;producer&lt;/strong&gt; for the OKF ecosystem — not affiliated with Google, not part of the OKF spec repository. It has one job: take a software repository's raw artifacts and continuously compile them into an OKF-conformant knowledge base that stays in sync as the repository changes.&lt;/p&gt;

&lt;p&gt;The "compiler" framing is deliberate and precise, not marketing. A compiler is a piece of software with a defined input grammar, a deterministic pass over that input, and a reproducible output — not a one-shot LLM summarization job you re-run and hope produces something similar to last time. Open Knowledge Compiler treats knowledge extraction the same way a real compiler treats source code: parse what you can deterministically, treat inference (the LLM layer) as an optional enrichment pass on top, and never let inference decide identity.&lt;/p&gt;

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

&lt;p&gt;Six stages, always in this order: &lt;strong&gt;Collect&lt;/strong&gt; (Git, PRs, optionally Jira) → &lt;strong&gt;Extract&lt;/strong&gt; (deterministic parsing, then an optional LLM pass) → &lt;strong&gt;Normalize&lt;/strong&gt; (turn raw facts into stable, identified entities) → &lt;strong&gt;Diff&lt;/strong&gt; (compute what changed) → &lt;strong&gt;Persist&lt;/strong&gt; (one atomic transaction into Postgres) → &lt;strong&gt;Emit&lt;/strong&gt; (render the OKF wiki bundle from whatever's now in the database).&lt;/p&gt;

&lt;p&gt;The database is the durable source of truth. The OKF bundle is a &lt;em&gt;render&lt;/em&gt; of it — disposable, regenerated wholesale on every compile, never hand-edited. If a page in the wiki is wrong, the fix is in the compiler or the source data, not the Markdown file.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's actually implemented today
&lt;/h2&gt;

&lt;p&gt;This is the section where I'd rather under-claim than over-claim. Here's a plain accounting of what exists and runs, versus what's designed-for but not yet built.&lt;/p&gt;

&lt;h3&gt;
  
  
  The deterministic core (works with zero LLM, zero API keys)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Language analysis&lt;/strong&gt;: Python and TypeScript, parsed via &lt;a href="https://tree-sitter.github.io/tree-sitter/" rel="noopener noreferrer"&gt;tree-sitter&lt;/a&gt; running in-process — no Node.js runtime required. This produces &lt;code&gt;component&lt;/code&gt;, &lt;code&gt;api&lt;/code&gt;, and &lt;code&gt;test_coverage&lt;/code&gt; entities directly from AST structure: modules, symbols, HTTP routes and their handlers, which tests cover which code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Git and PR history&lt;/strong&gt;: a Git collector plus a forge (GitHub) collector that associates pull requests with the entities their diffs touch — via the forge API, not commit parentage, because squash/rebase merges rewrite history and would otherwise silently break this.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stable identity across recompiles&lt;/strong&gt;: this is the unglamorous, hardest-to-get-right piece. Every entity gets a &lt;strong&gt;slug&lt;/strong&gt; — &lt;code&gt;component/billing-rules&lt;/code&gt;, &lt;code&gt;api/get-discount&lt;/code&gt; — and that slug has to survive a second, third, hundredth recompile without churning, or every downstream link, every agent query, every wiki cross-reference breaks on every run. Deterministic entities get natural keys (a component's slug comes from its file path and symbol structure). LLM-derived entities go through a match-then-mint cascade — try to match an existing entity by external key, then anchor overlap, then name similarity, and only mint a new slug if nothing matches. The LLM never assigns identity; identity is decided by deterministic rules that happen to consult LLM output.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An append-only delta log&lt;/strong&gt;: every compile records exactly what was added, changed, removed, or moved, in one atomic transaction. "What changed in this repo in the last week" is a database query, not a diff of Markdown files.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The optional semantic layer (opt-in, requires an LLM provider)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;LLM-derived entities&lt;/strong&gt;: &lt;code&gt;feature&lt;/code&gt;, &lt;code&gt;business_rule&lt;/code&gt;, and &lt;code&gt;risk&lt;/code&gt; — things no AST can see, because they're about &lt;em&gt;intent&lt;/em&gt;, not &lt;em&gt;structure&lt;/em&gt;. "This function exists because refunds must be capped at 20% of order value" is a business rule; tree-sitter cannot extract that, an LLM reading the code and its context can.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Four provider integrations&lt;/strong&gt;: Anthropic, OpenAI, Azure OpenAI, and Cloudflare Workers AI, behind one thin interface — so swapping providers is a config change, not a rewrite.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A content-addressed cache&lt;/strong&gt;: every LLM call is cached by a hash of (prompt template version, model, input content). Re-running a compile on unchanged files costs nothing — the cache serves the prior answer, byte-identical, which is also what keeps entity identity stable across runs. This is the mechanism that makes "recompile the whole repo cheaply" true rather than aspirational.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A Jira collector&lt;/strong&gt;: opt-in, fetches issues linked from a merged PR's title or body, mints &lt;code&gt;jira_story&lt;/code&gt; entities and links them to the PRs that closed them.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Retrieval and the MCP server
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hybrid search&lt;/strong&gt;: PostgreSQL full-text search always available; optional embeddings (pgvector) fused with keyword results via reciprocal rank fusion when enabled. No embeddings configured? Search still works, keyword-only — retrieval degrades gracefully, it doesn't fail.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A read-only MCP server&lt;/strong&gt; (&lt;code&gt;kc serve&lt;/code&gt;) — this is the part that turns the OKF bundle from something an agent &lt;em&gt;reads&lt;/em&gt; into something an agent &lt;em&gt;queries&lt;/em&gt;. It exposes:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What it answers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;search_knowledge&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hybrid keyword + semantic search over everything compiled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_entity&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Full detail for one entity: payload, source anchors, relationships, provenance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;impact_plan&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;"If I change this, what else in the repo is affected?"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;resolve_dependency&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Resolves an import/package coordinate to another compiled repo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;list_entities&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Every entity of a given type&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;recent_changes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;What changed in the last N compiles&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;which_pr_introduced&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Which PR (or the bootstrap compile) first added this entity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;coverage_for&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Which tests cover this component&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;knowledge_stats&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Entity counts, last compile metadata&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;test_plan&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Concrete coverage gaps for a component, as targets an agent could act on&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The server never compiles anything — it's read-only, always. Compilation is a separate, CI-triggered step. This matters for the same reason a database's read replica and its write path are usually different concerns: you don't want an agent's queries able to mutate the knowledge base it's querying.&lt;/p&gt;

&lt;h3&gt;
  
  
  OKF conformance — checked, not assumed
&lt;/h3&gt;

&lt;p&gt;This is the piece I want to be most transparent about, because it's also the most interesting story from actually building this.&lt;/p&gt;

&lt;p&gt;The wiki emitter was originally built against an early draft of the OKF spec. While writing this announcement and researching the spec's actual GitHub repository directly, it became clear the authoritative spec had already moved to &lt;strong&gt;v0.2&lt;/strong&gt; — with real, breaking changes from that earlier draft (a &lt;code&gt;timestamp&lt;/code&gt; field renamed to a &lt;code&gt;generated: {by, at}&lt;/code&gt; object; provenance moved from a body-text &lt;code&gt;# Citations&lt;/code&gt; section into a &lt;code&gt;sources&lt;/code&gt; frontmatter array; stricter rules for the two reserved filenames).&lt;/p&gt;

&lt;p&gt;That discovery surfaced actual bugs — not stylistic drift, real conformance failures: the wiki's &lt;code&gt;index.md&lt;/code&gt; was emitting frontmatter fields the spec explicitly forbids there; a &lt;code&gt;sources&lt;/code&gt; key was colliding in name (but not shape) with the spec's own provenance vocabulary. Those got fixed. Two things came out of fixing them:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;kc validate-okf&lt;/code&gt;&lt;/strong&gt; — a command that checks an emitted bundle against the actual conformance rules (parseable frontmatter, a non-empty &lt;code&gt;type&lt;/code&gt; field, reserved-filename structure) rather than assuming the emitter got it right.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;kc compile --emit-only&lt;/code&gt;&lt;/strong&gt; — because a spec-version bump only ever needs to change how already-compiled knowledge is &lt;em&gt;rendered&lt;/em&gt;, this re-runs just the Emit stage against the database, with no new compile, no re-parsing, no LLM calls. Rolling out a spec update across every repo you've compiled is cheap by construction, not something you re-pay full compile cost for.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Every compile run now records which OKF version its wiki targeted (&lt;code&gt;okf_spec_version&lt;/code&gt;), the same way it already tracked its own fact and entity schema versions. This is recorded in &lt;a href="https://github.com/kushal-omnius/open-knowledge-compiler/blob/main/docs/decisions/ADR-013-open-source-okf-conformance.md" rel="noopener noreferrer"&gt;ADR-013&lt;/a&gt;, one of thirteen architectural decision records that document &lt;em&gt;why&lt;/em&gt; the system is built the way it is, not just what it does.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Honest nuance&lt;/strong&gt;: conformance here means the &lt;em&gt;required&lt;/em&gt; and &lt;em&gt;recommended&lt;/em&gt; fields (&lt;code&gt;type&lt;/code&gt;, &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;description&lt;/code&gt;, &lt;code&gt;resource&lt;/code&gt;, &lt;code&gt;tags&lt;/code&gt;) plus the correctly-shaped &lt;code&gt;generated&lt;/code&gt; provenance block. The newer optional OKF v0.2 families — &lt;code&gt;verified&lt;/code&gt; trust tiers, &lt;code&gt;status&lt;/code&gt;/&lt;code&gt;stale_after&lt;/code&gt; lifecycle fields, the &lt;code&gt;Attested Computation&lt;/code&gt; concept type for verifiable, executable knowledge — are not populated by Knowledge Compiler today. They're real, interesting extension points; they're future work, not shipped features.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Where the producer/consumer split actually matters
&lt;/h2&gt;

&lt;p&gt;OKF's own design insists producers and consumers stay independent, and this is worth taking seriously rather than treating as a spec footnote — it's the reason this tool is useful to people who will never install it.&lt;/p&gt;

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

&lt;p&gt;Anyone can point a generic OKF viewer, a search indexer, or a completely different agent framework at a bundle Open Knowledge Compiler produced, without installing Knowledge Compiler or touching its database. Conversely, Knowledge Compiler's compiled Postgres database is genuinely useful (via &lt;code&gt;kc serve&lt;/code&gt;'s MCP tools) even to someone who's never heard of OKF — the OKF bundle is one &lt;em&gt;output&lt;/em&gt; of the system, not the whole point of it.&lt;/p&gt;




&lt;h2&gt;
  
  
  For humans, and for agents — genuinely different experiences of the same knowledge
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;For a human&lt;/strong&gt;, the output is a wiki. Push the &lt;code&gt;knowledge/wiki&lt;/code&gt; branch (the reference publisher target — the destination is pluggable, GitHub Pages and Confluence publishers are additive, not built yet) and GitHub renders it as ordinary Markdown pages, cross-linked, with an &lt;code&gt;index.md&lt;/code&gt; you can click through. No special tooling to read it. That's the whole point of choosing "just Markdown, just files" as the substrate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For an agent&lt;/strong&gt;, there are two genuinely different ways in, and it's worth being precise about which one you're using:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Read the OKF bundle directly&lt;/strong&gt; — any agent, any tool, zero KC-specific integration. It's Markdown with YAML frontmatter; every modern coding agent already knows how to read that.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query the MCP server&lt;/strong&gt; — this is richer than reading files, because it's not just retrieval, it's &lt;em&gt;structured traversal of a graph&lt;/em&gt;: "what does changing this component affect," "resolve this import to the repo it actually lives in," "what covers this with tests." That's a live query over the compiled database, not a grep over rendered Markdown.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Neither path requires the other. An agent that only speaks "read files" still gets a synchronized, provenance-carrying knowledge base. An agent that speaks MCP gets the graph underneath the Markdown.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real numbers, not hypotheticals
&lt;/h2&gt;

&lt;p&gt;Knowledge Compiler has been dogfooded on real, private codebases — one primary service repository, one library it depends on, and on its own source tree. These are actual compiled states as of this writing, not illustrative examples:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Repository&lt;/th&gt;
&lt;th&gt;Entities&lt;/th&gt;
&lt;th&gt;Relationships&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Primary service repo&lt;/td&gt;
&lt;td&gt;3,016&lt;/td&gt;
&lt;td&gt;4,555&lt;/td&gt;
&lt;td&gt;105 APIs, 51 business rules, 554 features, 263 risks extracted with the LLM layer enabled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A library it depends on&lt;/td&gt;
&lt;td&gt;967&lt;/td&gt;
&lt;td&gt;1,413&lt;/td&gt;
&lt;td&gt;Compiled separately, linked via cross-repo dependency resolution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open Knowledge Compiler (itself)&lt;/td&gt;
&lt;td&gt;458&lt;/td&gt;
&lt;td&gt;880&lt;/td&gt;
&lt;td&gt;Compiled with &lt;code&gt;--no-llm&lt;/code&gt; — deterministic entities only&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That third row is worth pausing on: &lt;strong&gt;the tool compiles itself&lt;/strong&gt;. &lt;code&gt;kc verify&lt;/code&gt; — a zero-write shadow compile that checks the incrementally-maintained state against a full recompile — reports the compiled state of Open Knowledge Compiler's own repository as equivalent to a fresh full compile. &lt;code&gt;kc validate-okf&lt;/code&gt; reports the resulting bundle as fully conformant against OKF v0.2. Self-hosting a compiler on its own source is a real, verifiable claim, not a metaphor.&lt;/p&gt;

&lt;p&gt;The cross-repo case is a real scenario worth spelling out, because it's the one that comes up constantly in any codebase with more than one repository: Repo A depends on a library, Repo B. Compile both into the same database, add one line to Repo A's config mapping the import prefix to Repo B's registered name, and &lt;code&gt;resolve_dependency&lt;/code&gt; will resolve &lt;code&gt;some_lib.SomeClass&lt;/code&gt; to the actual compiled entity in Repo B — its payload, its relationships, its provenance — without Repo A's compile ever reading across the repository boundary at compile time. This is deliberately a query-time-only mechanism (&lt;a href="https://github.com/kushal-omnius/open-knowledge-compiler/blob/main/docs/decisions/ADR-011-cross-repo-dependency-resolution.md" rel="noopener noreferrer"&gt;ADR-011&lt;/a&gt;) — no shared schema changes, no cross-repository writes, nothing that risks one repo's compile depending on another's compile order.&lt;/p&gt;




&lt;h2&gt;
  
  
  What this is not (yet)
&lt;/h2&gt;

&lt;p&gt;Being specific about the boundary matters more than the feature list, so here it is plainly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Not a plugin ecosystem — yet.&lt;/strong&gt; The architecture is designed around pluggable stages (collectors, extractors, LLM providers, retrieval strategies, publishers), discovered via standard Python packaging entry points and activated only by explicit configuration — never by merely being installed, which is the property that keeps compilation reproducible. Today, the built-in plugins (the Python/TypeScript analyzers, the Git and Jira collectors, the four LLM providers) are wired directly rather than through that discovery mechanism; the entry-point activation path is designed but not yet the live path. Third-party plugins aren't a real, working story yet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not proven at large scale.&lt;/strong&gt; The architecture targets repositories up to roughly 5 million lines of code. The actual dogfood evidence above is on repositories in the hundreds to low thousands of compiled entities. That's real, verifiable evidence at the scale it exists at — it is not evidence of behavior at 5M LOC.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No version-pinned or release-aware queries.&lt;/strong&gt; "What changed in this dependency between the version I'm pinned to and the latest" is not answerable today. It's an explicitly deferred design item, not a bug.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No database-less mode.&lt;/strong&gt; Every compile requires PostgreSQL. There's an explicit, written-down design exploration for a lighter-weight mode that would trade away cross-run identity stability and the delta log for zero infrastructure — but it's a parked brainstorm document, not a roadmap commitment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not affiliated with Google or the OKF spec authors.&lt;/strong&gt; This is an independent, third-party implementation targeting a spec Google published and continues to evolve. If OKF changes again — and its own versioning policy says it will — Knowledge Compiler has to track that, the same ongoing-maintenance category of cost it already accepts for tree-sitter grammars and LLM provider APIs changing underneath it.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Trying it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/kushal-omnius/open-knowledge-compiler.git
&lt;span class="nb"&gt;cd &lt;/span&gt;open-knowledge-compiler
python &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; venv&lt;span class="se"&gt;\S&lt;/span&gt;cripts&lt;span class="se"&gt;\a&lt;/span&gt;ctivate   &lt;span class="c"&gt;# or source venv/bin/activate&lt;/span&gt;
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; .[all]
docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;                            &lt;span class="c"&gt;# Postgres + pgvector&lt;/span&gt;

&lt;span class="c"&gt;# Point it at any local git repo&lt;/span&gt;
kc init &lt;span class="nt"&gt;--slug&lt;/span&gt; my-service &lt;span class="nt"&gt;--forge-ref&lt;/span&gt; github.com/you/my-service &lt;span class="nt"&gt;--dir&lt;/span&gt; /path/to/repo
kc compile &lt;span class="nt"&gt;--full&lt;/span&gt; &lt;span class="nt"&gt;--no-llm&lt;/span&gt; &lt;span class="nt"&gt;--dir&lt;/span&gt; /path/to/repo  &lt;span class="c"&gt;# deterministic pass, no API keys needed&lt;/span&gt;
kc inspect &lt;span class="nt"&gt;--dir&lt;/span&gt; /path/to/repo                  &lt;span class="c"&gt;# see what got compiled&lt;/span&gt;
kc validate-okf &lt;span class="nt"&gt;--dir&lt;/span&gt; /path/to/repo             &lt;span class="c"&gt;# confirm the emitted bundle is OKF-conformant&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No API keys, no LLM provider, no embeddings configuration required to see real output. Enabling the semantic layer (&lt;code&gt;[llm] enabled = true&lt;/code&gt; in the generated &lt;code&gt;kc.toml&lt;/code&gt;) and embeddings (&lt;code&gt;[embeddings] enabled = true&lt;/code&gt;) are both later, opt-in steps, each independently toggleable.&lt;/p&gt;




&lt;h2&gt;
  
  
  The direction this is heading — clearly marked as direction, not done
&lt;/h2&gt;

&lt;p&gt;Everything above this line is real and running. Everything in this section is where the project is aimed, and none of it should be read as already built:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A real plugin ecosystem&lt;/strong&gt;, once the built-in plugins have proven the interfaces stable enough to hand to third parties — the current wiring is deliberately the simple path until that trigger fires, not a permanent decision.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Version-aware queries&lt;/strong&gt; across compiled repositories — "what changed in this dependency between the two versions I care about" — as a thin layer over the existing delta log rather than a new storage mechanism.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Additional OKF v0.2 field families&lt;/strong&gt; — trust tiers, staleness lifecycle, and eventually mapping something like mutation-kill-rate data onto the &lt;code&gt;Attested Computation&lt;/code&gt; concept type, so a business rule's compiled entity could carry a verifiable, re-runnable check rather than just a description.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The long-term evaluation question&lt;/strong&gt;: whether knowledge compiled this way measurably improves what AI agents produce when working in a codebase — code changes, generated tests, answers to engineering questions — compared to an agent with no compiled context at all. That's the actual north star. Everything described in this post is the infrastructure a fair test of that question requires; it is not, itself, evidence that the test has been run or won.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;Open Knowledge Format gives the ecosystem a shared, minimal answer to "what should a knowledge file look like." Open Knowledge Compiler answers a narrower, harder question underneath that: for a living software repository, where does that file's &lt;em&gt;content&lt;/em&gt; come from, and how does it stay true as the code keeps changing?&lt;/p&gt;

&lt;p&gt;The answer here is: deterministically wherever possible, an LLM only where structure genuinely can't reach, identity that survives recompilation, provenance on every fact, and a conformance checker that verifies the output rather than trusting the emitter. That's a compiler, in the actual sense of the word — and it's now open source, Apache-2.0, and running on real code today.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repository&lt;/strong&gt;: &lt;a href="https://github.com/kushal-omnius/open-knowledge-compiler" rel="noopener noreferrer"&gt;github.com/kushal-omnius/open-knowledge-compiler&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;License&lt;/strong&gt;: Apache-2.0&lt;br&gt;
&lt;strong&gt;Spec it targets&lt;/strong&gt;: &lt;a href="https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md" rel="noopener noreferrer"&gt;OKF v0.2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Contributions, issues, and honest skepticism are all welcome — see &lt;code&gt;CONTRIBUTING.md&lt;/code&gt; in the repo.&lt;/p&gt;

</description>
      <category>okf</category>
      <category>knowledgecompiler</category>
      <category>agents</category>
    </item>
    <item>
      <title>Diffey.in: The Online Text Comparison &amp; Diff Tool</title>
      <dc:creator>Kushal</dc:creator>
      <pubDate>Sat, 15 Nov 2025 14:13:25 +0000</pubDate>
      <link>https://dev.to/kushal/diffeyin-the-online-text-comparison-diff-tool-3h76</link>
      <guid>https://dev.to/kushal/diffeyin-the-online-text-comparison-diff-tool-3h76</guid>
      <description>&lt;h2&gt;
  
  
  Introducing Diffey: The Effortless Online Text Comparison &amp;amp; Diff Tool
&lt;/h2&gt;

&lt;p&gt;Have you ever found yourself struggling to spot the differences between two versions of a document, a piece of code, or even a simple block of text? Whether you’re a developer reviewing code, a writer editing drafts, or a student checking assignments, comparing text can be tedious and error-prone.&lt;/p&gt;

&lt;p&gt;That’s why I built &lt;a href="https://diffey.in/" rel="noopener noreferrer"&gt;Diffey — Free Online Text Comparison and Diff Tool&lt;/a&gt; — a free, privacy-friendly online diff tool designed to make text comparison fast, accurate, and enjoyable.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Why Diffey?
&lt;/h2&gt;

&lt;p&gt;There are plenty of diff-tools out there, but I wanted something that was&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Instant&lt;/strong&gt;: No sign-up, no installation, just open and compare.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Flexible&lt;/strong&gt;: Works for code, documents, essays, or any text.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Privacy-first&lt;/strong&gt;: Your data never leaves your browser.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;User-friendly&lt;/strong&gt;: Clean interface, easy to use, and accessible from any device.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Side-by-side Comparison&lt;/strong&gt;: Paste your texts into two editors and see differences highlighted in real time.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Granular Control&lt;/strong&gt;: Choose to compare by line, word, or character for the level of detail you need.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Handy Tools&lt;/strong&gt;: Swap, clear, and copy text with a single click.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Character Count&lt;/strong&gt;: Instantly see the length of each version.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Theme Toggle&lt;/strong&gt;: Switch between light and dark modes for comfortable viewing.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;No Cost, No Catch&lt;/strong&gt;: 100% free, with no ads or tracking.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Who Is Diffey For?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Developers&lt;/strong&gt;: Review code changes, debug, or check merge conflicts.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Writers &amp;amp; Editors&lt;/strong&gt;: Track revisions, compare drafts, or check for accidental changes.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Students &amp;amp; Teachers&lt;/strong&gt;: Spot similarities or differences in assignments and essays.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Anyone&lt;/strong&gt;: If you need to compare text, Diffey is for you!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to Use Diffey
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt; Visit &lt;a href="https://diffey.in/?ref=kushalbhalaik.xyz" rel="noopener noreferrer"&gt;diffey.in&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; Paste your two text versions into the “Version A” and “Version B” editors.&lt;/li&gt;
&lt;li&gt; Click “Compare” — differences are instantly highlighted.&lt;/li&gt;
&lt;li&gt; Adjust the diff granularity as needed, swap or clear text, and enjoy a distraction-free experience.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;I created Diffey to solve my own frustrations with clunky, privacy-invasive diff tools. My hope is that it helps you work faster and with more confidence, whether you’re coding, writing, or just curious about what’s changed.&lt;/p&gt;

&lt;p&gt;Give it a try and let me know what you think! Your feedback and suggestions are always welcome.&lt;/p&gt;

&lt;p&gt;Happy comparing!&lt;br&gt;
&lt;a href="https://diffey.in/?ref=kushalbhalaik.xyz" rel="noopener noreferrer"&gt;https://diffey.in&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also check out &lt;a href="https://diffey.in/givenwhenzen?ref=kushalbhalaik.xyz" rel="noopener noreferrer"&gt;GivenWhenZen — Online Gherkin Editor and Formatter by Diffey.in&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="https://www.kushalbhalaik.xyz/diffey/" rel="noopener noreferrer"&gt;&lt;em&gt;https://www.kushalbhalaik.xyz&lt;/em&gt;&lt;/a&gt; &lt;em&gt;on November 15, 2025.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>difftool</category>
      <category>textcomparison</category>
      <category>tooling</category>
      <category>productivity</category>
    </item>
    <item>
      <title>GivenWhenZen - A Free Online Gherkin Editor for BDD Enthusiasts by Diffey.in</title>
      <dc:creator>Kushal</dc:creator>
      <pubDate>Fri, 24 Oct 2025 16:28:27 +0000</pubDate>
      <link>https://dev.to/kushal/givenwhenzen-a-free-online-gherkin-editor-for-bdd-enthusiasts-2lbg</link>
      <guid>https://dev.to/kushal/givenwhenzen-a-free-online-gherkin-editor-for-bdd-enthusiasts-2lbg</guid>
      <description>&lt;p&gt;Hello, folks!!&lt;/p&gt;

&lt;p&gt;I come bearing news: I finally completed something that I wanted to work on for a long time: &lt;a href="https://diffey.in/givenwhenzen" rel="noopener noreferrer"&gt;GivenWhenZen&lt;/a&gt;-A Free Online Gherkin Editor/Formatter for BDD Enthusiasts.&lt;/p&gt;

&lt;h2&gt;
  
  
  🎯 Why I Built&amp;nbsp;This:
&lt;/h2&gt;

&lt;p&gt;As a QA developer deeply involved in BDD (Behavior-Driven Development), I often found myself switching between different tools to format and validate Gherkin feature files. Though there are a few options available, BUT I wanted something simpler-a clean, fast, browser-based editor/validator that just works. I vibe-coded it in a few hours, drawing inspiration from JSONlint.com.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  ✨ Key Features:
&lt;/h2&gt;

&lt;p&gt;• Real-time formatting with smart indentation&lt;br&gt;
• Instant validation and linting&lt;br&gt;
• Support for Cucumber, JBehave, and SpecFlow&lt;br&gt;
• Dark/Light theme options&lt;br&gt;
• Keyboard shortcuts for productivity&lt;br&gt;
• Zero setup required-works in your browser&lt;/p&gt;

&lt;h2&gt;
  
  
  💡 Built to&amp;nbsp;inspire:
&lt;/h2&gt;

&lt;p&gt;• Clean, minimalist UI inspired by modern code editors&lt;br&gt;
• Fast performance with instant feedback&lt;br&gt;
• Built using vanilla JavaScript for maximum performance&lt;br&gt;
• free to use&lt;/p&gt;

&lt;p&gt;• BDD practiti&lt;br&gt;
oners (anyone who used BDD in 2025)&lt;br&gt;
• QA engineers&lt;br&gt;
• Product owners writing acceptance criteria&lt;br&gt;
• Developers implementing Cucumber/SpecFlow tests&lt;/p&gt;

&lt;p&gt;🔗 Try it out: &lt;a href="https://diffey.in/givenwhenzen" rel="noopener noreferrer"&gt;https://diffey.in/givenwhenzen&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also try out the Diffey.in - Text Comparison &amp;amp; Diff Tool &lt;a href="https://diffey.in" rel="noopener noreferrer"&gt;Diffey.in - Text Comparison &amp;amp; Diff Tool&lt;/a&gt;&lt;/p&gt;

</description>
      <category>bdd</category>
      <category>testing</category>
      <category>cucumber</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Getting started with Deno</title>
      <dc:creator>Kushal</dc:creator>
      <pubDate>Sat, 15 Feb 2020 14:09:25 +0000</pubDate>
      <link>https://dev.to/kushal/getting-started-with-deno-3a4e</link>
      <guid>https://dev.to/kushal/getting-started-with-deno-3a4e</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2216%2F1%2AIyVGV5RGsrwkEc6z_hf_IQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2216%2F1%2AIyVGV5RGsrwkEc6z_hf_IQ.png" alt="Deno logo on https://deno.land"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this article, I’m going to show you how to get started with Deno — A secure runtime for JavaScript and TypeScript. We’ll see Installation of Deno, Hello World program and setting up an http-server.&lt;/p&gt;




&lt;h1&gt;
  
  
  The What?
&lt;/h1&gt;

&lt;p&gt;Deno is a secure runtime for Javascript &amp;amp; Typescript (right out of the box) just like Nodejs is a runtime for Javascript. Deno was created by same guy who created Nodejs i.e. Ryan Dahl.&lt;/p&gt;

&lt;p&gt;Deno aims to improve what Ryan Dahl thinks he should’ve done with Nodejs like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1448%2F0%2Au2FD3UvbYsgOJ1Lm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1448%2F0%2Au2FD3UvbYsgOJ1Lm.png" alt="**Deno aims to improve what’s wrong with Nodejs**"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1654%2F0%2AVVAL5csJzmPIeOts.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1654%2F0%2AVVAL5csJzmPIeOts.png" alt="**Things Deno offers out of the box**"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Installing Deno.
&lt;/h1&gt;

&lt;p&gt;There are few options available on official site &lt;a href="https://deno.land/" rel="noopener noreferrer"&gt;deno.land/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We are gonna install it using Power-shell command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`iwr https://deno.land/x/install/install.ps1 -useb | iex`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1716%2F0%2AyOGxGiwF0K2DXh_2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1716%2F0%2AyOGxGiwF0K2DXh_2.png" alt="**Message after Deno is successfully installed**"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Deno.exe executable file is stored in &lt;em&gt;C:\Users&amp;lt;username&amp;gt;.deno\bin\deno.exe&lt;/em&gt; by default.&lt;/p&gt;

&lt;p&gt;In macOS or Linux &lt;em&gt;$HOME/.local/bin&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Following command will give info about Deno, V8 Engine &amp;amp; Typescript version installed on your machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`deno --version`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1952%2F0%2AOyhpdNVACgsbpbb4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1952%2F0%2AOyhpdNVACgsbpbb4.png" alt="**Deno versions**"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Hello World — Writing first program with Deno.
&lt;/h1&gt;

&lt;p&gt;Open up your terminal and just type following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`deno [https://deno.land/std/examples/welcome.ts](https://deno.land/std/examples/welcome.ts)`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will result into:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1954%2F0%2AS10fbySzlSsJqWnp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1954%2F0%2AS10fbySzlSsJqWnp.png" alt="**Executing a remote .ts file**"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What happened here is we execute a code present in a remote file, AWESOME!!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1928%2F0%2A0pld_x7LauVJV2lG.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1928%2F0%2A0pld_x7LauVJV2lG.png" alt="**Content of [https://deno.land/std/examples/welcome.ts](https://deno.land/std/examples/welcome.ts)**"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let’s execute a local code:&lt;/p&gt;

&lt;p&gt;Create a file inside “C:\deno” &amp;gt; index.ts (it could have .js extension for a javascript file)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2216%2F0%2AZQl60kpAWMpkJcOl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2216%2F0%2AZQl60kpAWMpkJcOl.png" alt="**Opening index.ts in Visual Studio Code**"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now using terminal execute following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`deno index.ts`

`or`

`deno index.js`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1956%2F0%2AWV0aKKlghJblNd7h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1956%2F0%2AWV0aKKlghJblNd7h.png" alt="**Hello World!! with index.ts**"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1950%2F0%2AhkZqpSCOZAObfWnK.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1950%2F0%2AhkZqpSCOZAObfWnK.png" alt="**Hello World!! with index.js**"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Setting up an http-server.
&lt;/h1&gt;

&lt;p&gt;Deno provides an http-server i.e.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`[https://deno.land/std@v0.30.0/http/server.ts](https://deno.land/std@v0.30.0/http/server.ts)`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As provided on official website example, here’s how you can create a running server on your machine:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`import { serve } from "https://deno.land/std@v0.30.0/http/server.ts";`

`const s = serve({ port: 5000 });`

`console.log("Listening on http://localhost:5000/");`

`for await (const req of s) {
  req.respond({ body: "Hello World!!" });
}`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;just copy paste above code into your &lt;strong&gt;&lt;em&gt;“index.ts”&lt;/em&gt;&lt;/strong&gt; file and run it with following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`deno -A index.ts`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;-A flag provides all the necessary permission for your app to run on your machine&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2804%2F0%2A4FmvvxAYH6pg7ffh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2804%2F0%2A4FmvvxAYH6pg7ffh.png" alt="**GET request on server running on localhost:5000**"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Using Oak middle-ware with deno http server.
&lt;/h1&gt;

&lt;p&gt;Oak is a middleware framework for Deno’s net server, more on this can be found on GitHub repo: &lt;a href="https://github.com/oakserver/oak" rel="noopener noreferrer"&gt;https://github.com/oakserver/oak&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;NOW let’s create a GET &amp;amp; POST endpoint by altering our &lt;strong&gt;&lt;em&gt;“index.ts”&lt;/em&gt;&lt;/strong&gt; code with following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Application, Router } from "[https://deno.land/x/oak/mod.ts](https://deno.land/x/oak/mod.ts)";

const router = new Router();

router.get("/", context =&amp;gt; {
  context.response.body = "Hello World!";
});

router.post("/", context =&amp;gt; {
  context.response.body = "You have made a POST request!";
});

const app = new Application();

app.use(router.routes());
app.use(router.allowedMethods());

const server = app.listen({ port: 5000 });

console.log("Listening on [http://localhost:5000/](http://localhost:5000/)");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2804%2F0%2AeOYUPJH2BWf-HTFl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2804%2F0%2AeOYUPJH2BWf-HTFl.png" alt="**GET request on server running on localhost:5000**"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3840%2F0%2A6Qz7Ngh3PxAc6J9W.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3840%2F0%2A6Qz7Ngh3PxAc6J9W.png" alt="**POST request on server running on localhost:5000**"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, that was it regarding installing Deno, writing first ‘Hello-World” program and setting up an http-server along with Oak middleware.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resources:&lt;/strong&gt;&lt;br&gt;
Deno — a better Node.js? | Krzysztof Piechowicz : &lt;a href="https://www.youtube.com/watch?v=mzfw9TwBiQc&amp;amp;t=616s" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=mzfw9TwBiQc&amp;amp;t=616s&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Deno Examples: &lt;a href="https://deno.land/#example" rel="noopener noreferrer"&gt;https://deno.land/#example&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Oak Middleware: &lt;a href="https://github.com/oakserver/oak" rel="noopener noreferrer"&gt;https://github.com/oakserver/oak&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Original article on&lt;/strong&gt;: &lt;a href="https://blog.kushalbhalaik.xyz/getting-started-with-deno/" rel="noopener noreferrer"&gt;https://blog.kushalbhalaik.xyz/getting-started-with-deno/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>deno</category>
      <category>oakserver</category>
      <category>node</category>
    </item>
    <item>
      <title>GitHub Pages — A Comprehensive guide w/ images (Part 2)</title>
      <dc:creator>Kushal</dc:creator>
      <pubDate>Sun, 12 Jan 2020 07:00:28 +0000</pubDate>
      <link>https://dev.to/kushal/github-pages-a-comprehensive-guide-w-images-part-2-nno</link>
      <guid>https://dev.to/kushal/github-pages-a-comprehensive-guide-w-images-part-2-nno</guid>
      <description>&lt;p&gt;This is part 2 of the article series &lt;a href="https://dev.to/far11ven/github-pages-a-comprehensive-guide-w-images-part-1-a56"&gt;&lt;em&gt;GitHub Pages — A Comprehensive guide w/ images&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iH_VnJWC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/8470/0%2AV_dX9tSJhBRw3S9q" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iH_VnJWC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/8470/0%2AV_dX9tSJhBRw3S9q" alt="Photo by [Sincerely Media](https://unsplash.com/@sincerelymedia?utm_source=medium&amp;amp;utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&amp;amp;utm_medium=referral)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Recently I started building my personal &lt;a href="https://kushalbhalaik.xyz"&gt;website&lt;/a&gt; as everyone is building one for themselves these days. I got a cool TLD (.xyz), and that is the only money I wanted to spend. Since then I’ve been looking for ways to host it without any costs.&lt;/p&gt;




&lt;p&gt;In &lt;a href="https://dev.to/far11ven/github-pages-a-comprehensive-guide-w-images-part-1-a56"&gt;part 1&lt;/a&gt; of this series we saw how to publish GitHub User Pages and how to link it with custom-domain.In this article we’ll see how to have more than one Github Pages per account (Yes, it is possible). &lt;em&gt;Commençons!!&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Before proceeding make sure you already have a repository .github.io&lt;/em&gt;
&lt;/h3&gt;

&lt;h1&gt;
  
  
  Setting up Multiple Github Pages:
&lt;/h1&gt;

&lt;p&gt;Let’s create a new repository:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Goto &lt;a href="http://www.github.new"&gt;Github.new&lt;/a&gt; and fill out the new repository details, I’ll call it &lt;strong&gt;demo&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FTrpqVFZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1782/1%2APzfpUhBsr5iJi5Q7QRK7Nw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FTrpqVFZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1782/1%2APzfpUhBsr5iJi5Q7QRK7Nw.png" alt="Repository creation flow on GitHub"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Note: It is important to keep this repository public
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Now goto repository settings:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0CgUfX9E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2030/1%2Ab5bPuFazwfRwghdXnAVjIg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0CgUfX9E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2030/1%2Ab5bPuFazwfRwghdXnAVjIg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;On Settings page, scroll down to &lt;strong&gt;Github Pages&lt;/strong&gt; section:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mfBDbv5i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2096/1%2A8yAgZCpugVwjaXM4eKXn7w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mfBDbv5i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2096/1%2A8yAgZCpugVwjaXM4eKXn7w.png" alt="GitHub Repo Settings Page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Make the repository Public, if you see following message:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--p0vs7ImM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2474/1%2Aylp1_d_vkORpLPyClx_JAA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--p0vs7ImM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2474/1%2Aylp1_d_vkORpLPyClx_JAA.png" alt="Making Repository Public on GitHub"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Once repository is Public &lt;strong&gt;GitHub Pages&lt;/strong&gt; will become enabled for the current repository&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6EI3xK2S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2030/1%2A8Y6mLRtnTRzIe3WmzTmgPA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6EI3xK2S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2030/1%2A8Y6mLRtnTRzIe3WmzTmgPA.png" alt="GitHub Pages options"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Click on &lt;strong&gt;None&lt;/strong&gt;, then view current options:&lt;br&gt;
we can either choose following options:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Using “master” branch of demo repository for publishing GitHub pages (Like in GitHub &lt;strong&gt;User Pages&lt;/strong&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Using /docs page under “master” branch for publishing GitHub Pages&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We’ll be using &lt;strong&gt;gh-pages&lt;/strong&gt; branch option which is currently not available as &lt;strong&gt;gh-pages&lt;/strong&gt; branch doesn’t exist for &lt;strong&gt;demo&lt;/strong&gt; repository as of yet&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DAsiZx9U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1672/1%2ACk5_flCgHvQ1dc2GpbeRSQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DAsiZx9U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1672/1%2ACk5_flCgHvQ1dc2GpbeRSQ.png" alt="By default None is selected for GitHub Pages"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Copy the &lt;strong&gt;demo&lt;/strong&gt; repository link:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fFeOcioC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2160/1%2AMYtVHN0W5VgMej0DXKA9fg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFeOcioC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2160/1%2AMYtVHN0W5VgMej0DXKA9fg.png" alt="Copying repository link from GitHub"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Now clone the repo to local machine:
Here, &lt;strong&gt;far11ven&lt;/strong&gt; is my GitHub username
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~$ git clone https://github.com/far11ven/demo.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create local &lt;strong&gt;gh-pages&lt;/strong&gt; branch and push it to GitHub:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~$ cd demo
~$ git branch gh-pages
~$ git push remote -u origin gh-pages
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Go back to &lt;strong&gt;demo&lt;/strong&gt; settings on GitHub and select &lt;strong&gt;gh-pages&lt;/strong&gt; as source for publishing:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zSgCzQhh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1698/1%2AweFkH-xTZ-jYPsMeEfqbFA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zSgCzQhh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1698/1%2AweFkH-xTZ-jYPsMeEfqbFA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After this step whatever you put in &lt;strong&gt;gh-pages&lt;/strong&gt; branch will be automatically published.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Let’s create a simple &lt;strong&gt;index.html&lt;/strong&gt; file within this repository:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~$ echo “Hello gh-pages!!” &amp;gt; index.html
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Add, commit and push your changes to GithHub remote:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~$ git add *
~$ git commit -m “Initial commit”
~$ git push -u origin gh-pages
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;You can see in your browser &lt;strong&gt;demo&lt;/strong&gt; repository has been published&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1xF2xY6R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1302/1%2AWhTtLYp5oPJm8ye_b5jglg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1xF2xY6R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1302/1%2AWhTtLYp5oPJm8ye_b5jglg.png" alt="“demo” page published under GitHub User page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You will have a main GitHub User Page (One per account) &lt;strong&gt;username.github.io&lt;/strong&gt; and all other repos will be published as sub pages&lt;/p&gt;

&lt;p&gt;or,&lt;/p&gt;

&lt;p&gt;if you have already linked a custom-domain to your GitHub User Page, the n you can see the published page at &lt;strong&gt;&lt;a href="http://www.example.com/your-repo-name"&gt;www.example.com/your-repo-name&lt;/a&gt;&lt;/strong&gt;&lt;br&gt;
in my case &lt;strong&gt;demo&lt;/strong&gt; repo will be published at &lt;strong&gt;far11ven.github.io/demo&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h1&gt;
  
  
  Setting up custom-domains:
&lt;/h1&gt;

&lt;h1&gt;
  
  
  i) Setting up Github Pages as a domain
&lt;/h1&gt;

&lt;p&gt;To have our subpages be listed as demo page we need to do following changes in our GitHub repo and our Domain provider&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a &lt;strong&gt;CNAME&lt;/strong&gt; file in your repository:
I will be doing it via GitHub UI, just create a &lt;strong&gt;CNAME&lt;/strong&gt; file (with no extension) and just enter your sub-domain name inside it, nothing else.
in my case, I want to make &lt;strong&gt;demo&lt;/strong&gt; pages appear as &lt;strong&gt;your-website.com&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3AaMXtO7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2618/1%2AgEHiZyGl4ahG1Pzof-Q99A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3AaMXtO7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2618/1%2AgEHiZyGl4ahG1Pzof-Q99A.png" alt="CNAME File content"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once Done, commit your changes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--x15RXeMG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2032/0%2AYoWI7xR6nMUVX4gz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--x15RXeMG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2032/0%2AYoWI7xR6nMUVX4gz.png" alt="Adding CNAME to repository"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fTWBO6qr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2184/1%2AH59ALuDL9jcNg5o9Ll7z1A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fTWBO6qr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2184/1%2AH59ALuDL9jcNg5o9Ll7z1A.png" alt="After Adding CNAME to repo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add a new DNS record on your DNS provider:
We need to change existing CNAME records to point to created GitHub pages i.e. &lt;strong&gt;username.github.io&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HdTZuxlL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2620/1%2AFFgsmzUt4eV_r0MhCxAslw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HdTZuxlL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2620/1%2AFFgsmzUt4eV_r0MhCxAslw.png" alt="Adding new CNAME DNS record on Cloudflare"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  ii) Setting up Github Pages as a sub-domain:
&lt;/h1&gt;

&lt;p&gt;To have our subpages be listed as demo page we need to do following changes in our GitHub repo and our Domain provider&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create or Edit an existing &lt;strong&gt;CNAME&lt;/strong&gt; file in your repository:
I will be doing it via GitHub UI, in my case, there is already a CNAME File so I ‘ll just edit the existing file and replace everything in it with my sub-domain, nothing else.
in my case, I want to make &lt;strong&gt;demo&lt;/strong&gt; pages appear as &lt;strong&gt;demo.kushalbhalaik.xyz&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8ZXdcGjU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2234/1%2AFxyNYdcrL9TbOiA7uhYT-g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8ZXdcGjU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2234/1%2AFxyNYdcrL9TbOiA7uhYT-g.png" alt="CNAME File Content"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once Done, commit your changes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uV9TXSD2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2584/1%2AWu67RaNVR96RrX-NYkr0YQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uV9TXSD2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2584/1%2AWu67RaNVR96RrX-NYkr0YQ.png" alt="Editing CNAME file in Repository"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fTWBO6qr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2184/1%2AH59ALuDL9jcNg5o9Ll7z1A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fTWBO6qr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2184/1%2AH59ALuDL9jcNg5o9Ll7z1A.png" alt="After Adding CNAME to repo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add a new DNS record on your DNS provider for existing Domain:
We need to change existing CNAME records to point to created GitHub pages i.e. &lt;strong&gt;username.github.io&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uUaxc7XP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2092/1%2AxYlbopBao6uHGWPlScKDEA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uUaxc7XP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2092/1%2AxYlbopBao6uHGWPlScKDEA.png" alt="Adding new CNAME DNS record on Cloudflare"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Important Points:
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Again, at this point, nothing needs to be done from our end, we need to wait for changes to reflect on both GitHub and Cloudflare end, Which may take some time (usually its prompt) but may take some time based on your DNS provider&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You won’t be able to access your pages via &lt;strong&gt;username.github.io&lt;/strong&gt;, or &lt;strong&gt;username.github.io/our-repo&lt;/strong&gt;in case you try and enter this in browser, you’ll be redirected to your custom domain or custom sub-domain&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your can-not add multiple GitHub Pages as a sub-doman to &lt;strong&gt;GitHub User Page&lt;/strong&gt; i.e &lt;strong&gt;demo.far11ven.github.io&lt;/strong&gt; in my case is not a valid url&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Final Result:
&lt;/h1&gt;

&lt;p&gt;We have successfully created a sub-domain to host our another github-page, follow these steps to create even more pages within your website.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CU4WkqYK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1202/1%2AVptsVQstgH05Bm_OFdfhzQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CU4WkqYK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1202/1%2AVptsVQstgH05Bm_OFdfhzQ.png" alt="GitHub pages published under a sub-domain"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cheers!!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Original article on&lt;/strong&gt;: &lt;a href="https://blog.kushalbhalaik.xyz/github-pages-a-comprehensive-guide-w-images-part-2/"&gt;https://blog.kushalbhalaik.xyz/github-pages-a-comprehensive-guide-w-images-part-2/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>github</category>
      <category>githubpages</category>
      <category>staticwebsite</category>
      <category>html</category>
    </item>
    <item>
      <title>GitHub Pages — A Comprehensive guide w/ images (Part 1)</title>
      <dc:creator>Kushal</dc:creator>
      <pubDate>Sat, 11 Jan 2020 16:45:56 +0000</pubDate>
      <link>https://dev.to/kushal/github-pages-a-comprehensive-guide-w-images-part-1-a56</link>
      <guid>https://dev.to/kushal/github-pages-a-comprehensive-guide-w-images-part-1-a56</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wocw5Ka4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/8470/0%2AZVxZaN_2nnFSVQuK" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wocw5Ka4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/8470/0%2AZVxZaN_2nnFSVQuK" alt="Photo by [Sincerely Media](https://unsplash.com/@sincerelymedia?utm_source=medium&amp;amp;utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&amp;amp;utm_medium=referral)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Recently I started building my personal &lt;a href="https://kushalbhalaik.xyz"&gt;website&lt;/a&gt; as everyone is building for themselves these days. I got a cool TLD (.xyz), and that I is the only money I wanted to spend. Since then I’ve been looking for ways to host it without any costs.&lt;/p&gt;




&lt;p&gt;I’ve tried different host providers such as &lt;a href="http://www.heroku.com"&gt;Heroku&lt;/a&gt;, &lt;a href="http://www.000webhost.com"&gt;000webhost&lt;/a&gt; so far, which are good options. My website is vastly static pages so far until I figure out how to have a cms such as &lt;a href="http://www.ghost.org"&gt;Ghost&lt;/a&gt; to be integrated with &lt;a href="http://www.gatsbyjs.org"&gt;Gatsby&lt;/a&gt; for adding content periodically (Of course for free). Anyways I thought if my site is mostly static pages so why not give Github Pages a try (it’s been on my list for a quite sometime now) and along the way I encountered various hurdles and there wasn’t an elaborate article around it. So folks here we are :)&lt;/p&gt;

&lt;p&gt;This is part 1 of this article series, part 2 will be coming soon. &lt;em&gt;Enchanté&lt;/em&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Setting up Github Pages:
&lt;/h1&gt;

&lt;p&gt;This is the most straight forward thing, it’s all neatly illustrated here on &lt;a href="https://pages.github.com/"&gt;Github Pages&lt;/a&gt;, but as this article‘s name suggests I’m bound:&lt;/p&gt;

&lt;p&gt;We’ll start by creating a repository on Github:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Goto &lt;a href="https://github.com/new/"&gt;Github.new&lt;/a&gt;, a cooler way to create Github repositories (You’ll see).&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Make sure your repo-name is &lt;strong&gt;username.github.io&lt;/strong&gt;&lt;br&gt;
The pages ending with &lt;strong&gt;username.github.io&lt;/strong&gt; are called User Pages, where &lt;strong&gt;username&lt;/strong&gt; could belong to an individual or an organization&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cQU0KFdL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1698/1%2A0Ozb5XoyfFn7DWZspAYuAg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cQU0KFdL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1698/1%2A0Ozb5XoyfFn7DWZspAYuAg.png" alt="Repository creation flow on GitHub"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Note: It is important to make your repository Public, in order for your GitHub User pages to be accessible to all
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;We won’t be creating any other branch, because User Pages require to be built from master branch.&lt;br&gt;
And in this article, we won’t use Jekyll to publish our pages.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pNPhqUyr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1558/1%2Ano0kc3rdol3SWujmpJVKYg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pNPhqUyr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1558/1%2Ano0kc3rdol3SWujmpJVKYg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First clone the repo to local machine:
Here, &lt;strong&gt;username&lt;/strong&gt; is GitHub username
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~$ git clone https://github.com/username/username.github.io.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create an index.html file inside this repository:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~$ cd **username**.github.io

~$ echo “Hello World!!” &amp;gt; index.html
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Add, commit and push your changes to Github remote:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~$ git add *

~$ git commit -m “Initial commit”

~$ git push -u origin master
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Type {&lt;strong&gt;username.github.io&lt;/strong&gt;} in browser and you’re done publishing your first website to github pages.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SVsL2a5M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1022/1%2AXOuM4EPcUp2T2pOOniPaYw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SVsL2a5M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1022/1%2AXOuM4EPcUp2T2pOOniPaYw.png" alt="Browser screenshot of deployed Github pages"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Setting up Github Pages on your custom-domain:
&lt;/h1&gt;

&lt;p&gt;We have successfully created and deployed Github Pages. But I want users to visit my custom domain &lt;em&gt;kushalbhalaik.xyz.&lt;/em&gt; Lets link’em up:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Created a CNAME file in your repository:
I will be doing it via GitHub UI, just create a CNAME file (with no extension) and just enter your domain name inside it, nothing else.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ihb1dNyj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2052/1%2ApfBeNgjpAmuqIhBOQTgNHg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ihb1dNyj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2052/1%2ApfBeNgjpAmuqIhBOQTgNHg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once Done, commit your changes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yf-vLnOE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2032/1%2A_M1dh61vJyblyI6DX-m1CA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yf-vLnOE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2032/1%2A_M1dh61vJyblyI6DX-m1CA.png" alt="Adding CNAME file to repository"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Change DNS records on your DNS provider:
We need to change existing CNAME records to point to created github pages i.e. &lt;em&gt;username.github.io&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--T9IRGLtx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2116/1%2ARYZ6ZpXYVQmdEgXPqxGXuw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--T9IRGLtx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2116/1%2ARYZ6ZpXYVQmdEgXPqxGXuw.png" alt="Changing CNAME records on Cloudflare"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Important Points:
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;At this point, nothing needs to be done from our end, we need to wait for changes to reflect on both GitHub and Cloudflare end, Which may take some time (usually its prompt) but may take some time based on your DNS provider&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You won’t be able to access your pages via &lt;strong&gt;username.github.io&lt;/strong&gt;, in case you try and enter this in browser, you’ll be redirected to your custom domain&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So this was all to get you started with your very own Github Pages (User). In Part 2 of this series we’ll be taking deeper look into &lt;em&gt;gh-pages&lt;/em&gt; and linking pages to your sub-domain. &lt;em&gt;Stay Tuned!!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Original article on&lt;/strong&gt;: &lt;a href="https://blog.kushalbhalaik.xyz/github-pages-a-comprehensive-guide-w-images-part-1/"&gt;https://blog.kushalbhalaik.xyz/github-pages-a-comprehensive-guide-w-images-part-1/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>github</category>
      <category>githubpages</category>
      <category>staticwebsites</category>
      <category>html</category>
    </item>
    <item>
      <title>Bootstrap icons — Overview</title>
      <dc:creator>Kushal</dc:creator>
      <pubDate>Fri, 03 Jan 2020 05:42:26 +0000</pubDate>
      <link>https://dev.to/kushal/bootstrap-icons-overview-43m8</link>
      <guid>https://dev.to/kushal/bootstrap-icons-overview-43m8</guid>
      <description>&lt;h5&gt;
  
  
  &lt;a href="https://dev.to/t/bootstrap"&gt;#bootstrap&lt;/a&gt; &lt;a href="https://dev.to/t/html"&gt;#html&lt;/a&gt;
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Q6BSjl5K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2468/1%2A__FLgbyRXxBNwwps3yjV1w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Q6BSjl5K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2468/1%2A__FLgbyRXxBNwwps3yjV1w.png" alt="Bootstrap icons as seen on [http://icons.getbootstrap.com/](http://icons.getbootstrap.com/)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://getbootstrap.com/"&gt;Bootstrap&lt;/a&gt; is a large and complex frontend library which we all fancy having some powerful functionality and customization built-in. Occasionally though, when you need to have icons in your web projects; you go straight to&lt;a href="https://www.fontawesome.com/"&gt; Font-awesome&lt;/a&gt; or &lt;a href="https://getbootstrap.com/docs/3.3/components/"&gt;Glyphicons&lt;/a&gt; (Bootstrap v3). But developers and designers often felt constricted to the fact that they have to rely on some other third party library for the icons having to pay for icons they desire. This just didn’t seem right for any of us.&lt;/p&gt;

&lt;p&gt;Fast forward 2019, gone are the days when we had to choose between &lt;a href="https://www.fontawesome.com/"&gt;Font-awesome&lt;/a&gt; or &lt;a href="https://getbootstrap.com/docs/3.3/components/"&gt;Glyphicons&lt;/a&gt; (Bootstrap v3), For the first time ever, &lt;a href="https://getbootstrap.com/"&gt;Bootstrap&lt;/a&gt; has its own icon library, custom designed and built for its components… (&lt;code&gt;navbars&lt;/code&gt;, &lt;code&gt;button&lt;/code&gt;, &lt;code&gt;cards&lt;/code&gt;, and more).&lt;/p&gt;

&lt;p&gt;You can Track latest releases on Github &lt;a href="https://github.com/twbs/icons/releases/"&gt;here&lt;/a&gt;, also you can checkout Bootstrap icons &lt;a href="https://icons.getbootstrap.com/"&gt;documentation&lt;/a&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  Getting Started
&lt;/h1&gt;

&lt;h1&gt;
  
  
  With npm
&lt;/h1&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`npm install bootstrap-icons`
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Download
&lt;/h1&gt;

&lt;p&gt;Download the project from &lt;a href="https://github.com/twbs/icons/releases/"&gt;here&lt;/a&gt;, and from the &lt;code&gt;icons&lt;/code&gt; folder and directly copy icons SVGs which you require in your project.&lt;/p&gt;

&lt;h1&gt;
  
  
  Usage
&lt;/h1&gt;

&lt;p&gt;Choose how you would like to integrate Bootstrap icons in your web application.&lt;/p&gt;

&lt;h1&gt;
  
  
  External image
&lt;/h1&gt;

&lt;p&gt;Use directly from the project directory and reference them like normal images with the &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; element.&lt;/p&gt;

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

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`&amp;lt;img src="/assets/img/bootstrap.svg" width="64" height="64" title="Bootstrap"&amp;gt;`
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Preview:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TQvU52BA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/186/1%2Arh5okfViVbpCQFAkzzuCxg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TQvU52BA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/186/1%2Arh5okfViVbpCQFAkzzuCxg.png" alt="bootstrap.svg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Embedded
&lt;/h1&gt;

&lt;p&gt;Embed your icons within the HTML of your page (as opposed to an external image file). Here we’ve used a custom width and height.&lt;/p&gt;

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

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`&amp;lt;svg class="bi bi-chevron-right" width="64" height="64" viewBox="0 0 20 20" fill="currentColor" xmlns="http://www.w3.org/2000/svg"&amp;gt;
      &amp;lt;path fill-rule="evenodd" d="M6.646 3.646a.5.5 0 01.708 0l6 6a.5.5 0 010 .708l-6 6a.5.5 0 01-.708-.708L12.293 10 6.646 4.354a.5.5 0 010-.708z" clip-rule="evenodd"/&amp;gt;
&amp;lt;/svg&amp;gt;`
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Preview:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hX-KJEd1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/154/1%2AYZk5_5XFCm1W9fQ_m998aw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hX-KJEd1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/154/1%2AYZk5_5XFCm1W9fQ_m998aw.png" alt="chevron-right.svg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  As CSS
&lt;/h1&gt;

&lt;p&gt;You can also use the SVG within your CSS (be sure to escape any characters, such as &lt;code&gt;#&lt;/code&gt; to &lt;code&gt;%23&lt;/code&gt; when specifying hex color values). When no dimensions are specified via width and height on the &lt;code&gt;&amp;lt;svg&amp;gt;&lt;/code&gt;, the icon will fill the available space.&lt;/p&gt;

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

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`               .bi::before {
                              display: inline-block;
                              content: "";
                              background-image: url("data:image/svg+xml,&amp;lt;svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'&amp;gt;&amp;lt;path fill='none' stroke='%23333' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 14l6-6-6-6'/&amp;gt;&amp;lt;/svg&amp;gt;");
                              background-repeat: no-repeat;
                              background-size: 1rem 1rem;
                            }`
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Preview:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nk-rseWY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/184/1%2A1BMRBpqnP2FacIeCVNVVpg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nk-rseWY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/184/1%2A1BMRBpqnP2FacIeCVNVVpg.png" alt="image.svg"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Styling
&lt;/h1&gt;

&lt;p&gt;Color can be changed by setting a &lt;code&gt;.text-*&lt;/code&gt; class or custom CSS:&lt;/p&gt;

&lt;h1&gt;
  
  
  Using bootstrap css classes
&lt;/h1&gt;

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

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`&amp;lt;svg class="bi bi-alert-triangle text-danger" width="64" height="64" viewBox="0 0 20 20" fill="currentColor" xmlns="http://www.w3.org/2000/svg"&amp;gt;`

`                              ...`

`&amp;lt;/svg&amp;gt;`
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Preview:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NhoATRnz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/178/1%2AVr2CvOtaOoNgi1Dvo5e_hg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NhoATRnz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/178/1%2AVr2CvOtaOoNgi1Dvo5e_hg.png" alt="`alert-triangle.svg stylized with bootstrap class`"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Using custom css classes
&lt;/h1&gt;

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

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`.my-custom-css-class{
                      color:green;
                    }`
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Preview:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Cj-db5oW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/174/1%2AD3E5IizZSrXXmkt3ruScIg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Cj-db5oW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/174/1%2AD3E5IizZSrXXmkt3ruScIg.png" alt="`alert-triangle.svg stylized with custom css`"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Using Style Attribute
&lt;/h1&gt;

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

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`style="color:blue;"`
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Preview:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pbOPjSEL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/168/1%2AC72UxZhVkiRqyLdDQdNl0Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pbOPjSEL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/168/1%2AC72UxZhVkiRqyLdDQdNl0Q.png" alt="stylized `alert-triangle.svg`"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Original article on&lt;/strong&gt;: &lt;a href="https://blog.kushalbhalaik.xyz/bootstrap-icons-overview/"&gt;https://blog.kushalbhalaik.xyz/bootstrap-icons-overview/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>bootstrap</category>
      <category>html</category>
    </item>
    <item>
      <title>Email Templating with EJS (Node + Express + SendGrid)</title>
      <dc:creator>Kushal</dc:creator>
      <pubDate>Thu, 02 Jan 2020 06:54:18 +0000</pubDate>
      <link>https://dev.to/kushal/email-templating-with-ejs-node-sendgrid-l4k</link>
      <guid>https://dev.to/kushal/email-templating-with-ejs-node-sendgrid-l4k</guid>
      <description>&lt;h1&gt;
  
  
  nodejs #express #ejs
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F12032%2F1%2AMM2L7g1BEHa8ski3RCAM5A.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F12032%2F1%2AMM2L7g1BEHa8ski3RCAM5A.jpeg" alt="Photo by [Mockaroon](https://unsplash.com/@mockaroon?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/template?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’ve been building a social links website &lt;a href="https://www.8link.in/?ref=medium" rel="noopener noreferrer"&gt;8link&lt;/a&gt;, which requires me to interact with my users at different levels. So the type of email interaction with my users, I’ve narrowed it down to the following categories of emails:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Welcome email (With verify link)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Password reset link&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Automated response to user queries&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The actual response to User queries&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Occasional promo or newsletters&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I’ve been using a Node.js +Express back-end and I wanted to achieve it with same frame-work. So I started using SendGrid &lt;a href="https://sendgrid.com/solutions/email-api/" rel="noopener noreferrer"&gt;Email API&lt;/a&gt; to achieve this goal.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;SendGrid already has a Templating service, if you are interested you can check it &lt;a href="https://sendgrid.com/docs/ui/sending-email/how-to-send-an-email-with-dynamic-transactional-templates/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Back to Templating with EJS,&lt;br&gt;
in This article, we’ll see how can we create Re-Usable HTML Templates with EJS and then deliver them with SendGrid.&lt;/p&gt;

&lt;p&gt;We’ll start by creating a simple node project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm init sendgrid-mailer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Install following dependencies,&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i --save express cors ejs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Our Package.json should look like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1792%2F1%2A4KnnrY1HX6LCh8S7djHtNw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1792%2F1%2A4KnnrY1HX6LCh8S7djHtNw.png" alt="package.json file"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;Let’s create a simple endpoint to serve our email “/hello”&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Notice //set express view engine to ejs
app.set(“view engine”, “ejs”);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;it should give us the following response:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F960%2F1%2AbX6CnP-NNwnBN1Rxuh6v2w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F960%2F1%2AbX6CnP-NNwnBN1Rxuh6v2w.png" alt="/hello on localhost"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We are halfway there, Now create a &lt;em&gt;welcome-mail.ejs&lt;/em&gt; file in views (Template) folder in the project root directory.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F798%2F1%2A0dtPUAeab8tupUAwxjKfLg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F798%2F1%2A0dtPUAeab8tupUAwxjKfLg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now add some HTML code in there, which will serve as an underlying template for our welcome mail:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;You will see the following syntax in this HTML, which is used to receive data before rendering it. We are using the following variables for manipulating data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//these are EJS expressions to dynamically receive and display data while rendering an HTML

&amp;lt;%= user_firstname %&amp;gt;
&amp;lt;%= confirm_link %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now we need to make changes to our “/hello” endpoint&lt;/p&gt;

&lt;p&gt;We’ll need to import following to our index.js file:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//imports
const path = require(“path”);
const ejs = require(“ejs”);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;and our “/hello” app route function will change to :&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.get(“/hello”, (*req*, *res*, *next*) =&amp;gt; {
let emailTemplate;
let capitalizedFirstName = “John”;
let userEmail = “John@example.com”;

ejs
.renderFile(path.join(__dirname, “views/welcome-mail.ejs”),
{
  user_firstname: capitalizedFirstName,
  confirm_link: “http://www.8link.in/confirm=" + userEmail
})
.then(*result* =&amp;gt; {
  emailTemplate = result;
  res.send(emailTemplate);
})
.catch(*err* =&amp;gt; {
  res.status(400).json({
      message: “Error Rendering emailTemplate”,
      error: err
     });
  });

});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;in here, &lt;strong&gt;ejs.renderFile()&lt;/strong&gt; take .ejs file path and specify values for &lt;strong&gt;_user_firstname _&lt;/strong&gt;and &lt;strong&gt;&lt;em&gt;confirm_link&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now if we hit “/hello” we get:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3840%2F1%2AY5Gtffdna1ZO_N3J-X62xQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3840%2F1%2AY5Gtffdna1ZO_N3J-X62xQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Whoops..&lt;/strong&gt; we now have our welcome template, we just have to deliver it via email now.&lt;/p&gt;


&lt;h4&gt;
  
  
  Let's integrate SendGrid now:
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;First signup for SendGrid mail API, by clicking &lt;a href="https://sendgrid.com/docs/API_Reference/api_v3.html" rel="noopener noreferrer"&gt;here&lt;/a&gt; and get the API -KEY&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now get @sendgrid/mail package from npm.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i --save @sendgrid/mail
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Import following into &lt;strong&gt;index.js&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const SGmail = require(“@sendgrid/mail”);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now in our code first register the SendGrid API Key&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SGmail.setApiKey(process.env.SendGrid_Key);

//Note: store SendGrid_Key in your projects' config file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;and replace **res.send(emailTemplate); **with following code:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const message = {
  to: userEmail,
  from: { email: “welcome@8link.in”, name: “8link” },
  subject: “Welcome link”,
  html: emailTemplate
};

return SGmail.send(message).then(*sent* =&amp;gt; {

// Awesome Logic to check if mail was sent

   res.status(200).json({
      message: “Welcome mail was sent”

      });

}).catch(*err* =&amp;gt; {

      console.log(“Error sending mail”, err);
      res.status(400).json({
          message: “Welcome mail was not sent”,
          error: err
      });

});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Our final code should look like:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;And if I hit my “/hello” endpoint again, I should see that mail was sent successfully:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1512%2F1%2AV4fQgNhZOtrM7FzSkOEcRQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1512%2F1%2AV4fQgNhZOtrM7FzSkOEcRQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Full Code on Github: &lt;a href="https://github.com/far11ven/SendGrid-Mailer" rel="noopener noreferrer"&gt;https://github.com/far11ven/SendGrid-Mailer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Original article on&lt;/strong&gt;: &lt;a href="https://blog.kushalbhalaik.xyz/email-templating-with-ejs-node-express-sendgrid/" rel="noopener noreferrer"&gt;https://blog.kushalbhalaik.xyz/email-templating-with-ejs-node-express-sendgrid/&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
