Sr. Content Developer at Microsoft, working remotely in PA, TechBash conference organizer, former Microsoft MVP, Husband, Dad and Geek.
157619 stories
·
33 followers

In defense of polyfills

1 Share

If you’re a web developer, you may find the title baffling. “Polyfills need defending? Who’s against them?!” you might ask.

Two weeks ago, I’d be in the same boat.

Polyfills and I go way back. I dug up a JSConf EU talk of mine from 2011 on exactly this topic.

YouTube still from that talk
Trying not to think about how young I look here 😅

One of the few opinions I have held strongly over the years is that polyfills are a net positive for the Web, and the good outweighs the rare failure cases where polyfills became too popular, too soon, and restricted the design space for the native API.

As with most things in life, it’s all about the cost-benefit. We don’t stop flying planes because crashes happen. We do a post-mortem and figure out how we can prevent the same accident from happening again. And crucially, the point of a post-mortem is to find the root cause — not to ground the entire fleet.

Don’t get me wrong, concerns about polyfills are well-intentioned. They come from implementors and standards folks who want to preserve the design flexibility to build the best API surface possible — a goal I share deeply. Being both a spec editor and a library author, striking that balance is something I navigate all the time.

Still, I was under the impression that seeing polyfills as a net positive was the consensus view of the web standards community as a whole. That while we may not have consensus on the specific tradeoffs or solutions, we see polyfilling as a good thing and we generally do want web platform features to be polyfillable.

So, you can imagine my surprise when in a recent WHATWG meeting where I presented a proposal for extending mutation observers to observe shadow root attachment, Anne van Kesteren expressed the view that polyfilling is harmful.

Say what now?!

It’s important to note that Anne is not some rando. He is the main active editor of most WHATWG specs (HTML, DOM, Fetch, import maps, etc.), a WebKit engineer at Apple, and has tremendous overall influence on the direction of the Web platform.

I had to find out if Anne’s comment reflected broader committee consensus, so I brought the topic up in the WHATWG Matrix and asked some folks privately.

Thankfully, it became clear that no, Anne’s comment did not reflect broader consensus (😮‍💨), but some of the views expressed about polyfills were more ambivalent than I’d have expected.

As I said, these concerns are well-intentioned — but I believe they are generally misplaced. Most fail to consider the system holistically, and especially the human factors that drive developer behavior.

Let me explain.

It’s not the polyfills

Authors want to use native behavior when it exists, without breakage when it doesn’t. That’s the crux of it. That’s what restricts design flexibility.

Scooby do mask reveal meme with the first panel reading “Polyfills” and the second (revealed) reading “Progressive Enhancement”

Whenever this happens too early, by too many people, you can have a problem. It doesn’t matter whether the code using it is a polyfill, a fallback, “progressive enhancement” or “graceful degradation”.

Fundamentally, every pattern that uses the native feature when it exists and a userland implementation (or even nothing) when it doesn’t risks breakage if the feature changes in a way that is incompatible with that usage.

This includes:

  • Using CSS properties for progressive enhancement, accepting that they won’t work everywhere
  • CSS fallbacks via the cascade or @supports
  • Conditional imports after feature detection
  • Using a modern HTML element, with a script that converts it to (or wraps it with) a web component if not supported
  • Build tools that include fallbacks alongside the native feature
  • JS let foo = nativeThing?.() ?? fallbackThing()
  • etc etc

In all of these cases, if the native API were to change in a way incompatible with the fallback usage, stuff could break.

Eliminating polyfills does not eliminate the need for them.

The benefit of polyfills over the techniques above is author-facing: polyfills are portable, maintainable, and typically more correct than ad-hoc fallbacks.

When a bug is identified in a polyfill, it can be fixed centrally. When a bug is identified in an ad-hoc fallback strategy, good luck finding all the callsites and fixing them.

Bottom line: eliminating polyfills does not eliminate the need for them and all other avenues of satisfying that need are measurably worse.

Polyfills decouple API design from implementation

Standardized APIs have intrinsic value, independently of browser implementations.

We think of polyfills as a toggle: use a polyfill, leave it in there, and later when all browsers implement the feature natively, it gets removed.

This misses out on one of the biggest benefits of polyfills: decoupling API design from implementation.

If a userland library isn’t working well, you must weigh the tradeoffs of refactoring your codebase to use a different library, and educating your team about the new library.

With a polyfill, the API itself is not within the purview of the polyfill. The polyfill supplies only implementation, while the API is externally decided by the standards. Thus, swapping a misbehaving polyfill for another has near-zero cost.

The benefits of API standardization are far greater when we consider the broader ecosystem. A dependency isn’t aware what your userland implementation may be for certain functionality. Either it needs to provide a way to pass it via configuration (expanding its API surface), or it needs to implement its own version of the functionality, which may be incompatible with that of the host.

Standardized APIs are the town square of the Web, uniting all consumers (developers, agents, tooling, etc) around a shared vocabulary.

For example, suppose we’re using:

  • a data binding framework that synchronizes JS data with form controls
  • a library that reads form control values and stores them in localStorage until the form is submitted
  • a custom command invoker for copying the value of an arbitrary form control to the clipboard

As long as these are implemented in an element-agnostic way, reading element.value [1] and listening to input and change events, they will work with any form control that implements the same API, whether it’s a native HTML element or a custom element, allowing for loose coupling.

But without this standardized API, we need to specify how every custom element expresses its data and what event(s) it uses to notify for changes to each and every one of these libraries. This is user effort on the magnitude of O(M × N) on the number of consumers and producers that must know about each other. Standardized APIs collapse it to O(1).

Are separate namespaces the solution?

From the same WHATWG discussion:

Anne: I would much rather people write a library that demonstrates the need for something as opposed to something that attempts to mimic the exact API shape of a proposal while simultaneously trampling all over our design flexibility.

Anne: You want to enable people using the amount element? Fine, but call it [something]-amount.

Stephen: I see “library that implements some feature” and “polyfill” as synonymous, but I can also see that fails to capture everything.

Anne: When I hear polyfill I think specifically of things that attempt to occupy the exact same API space and tend to cause issues, such as we had recently with Scoped Custom Element Registries. We ended up with a much worse standardized API because of that.

The topic of polyfilling often comes up in discussions about CSS and HTML polyfilling, which are currently much harder to polyfill than JS features.

Many people are of the opinion that the solution is to have a separate namespace for polyfills, so they cannot conflict with native implementations. For example, instead of polyfilling <amount>, you’d create a web component that polyfills <polyfill-amount>. Instead of polyfilling the CSS property border-shape, you’d write a polyfill that makes --border-shape work the same way.

At first glance, this seems ideal: the benefits of polyfilling without the risk of syntax lock-in! But we’ve tried it before.

Who remembers vendor prefixes?

Their core premise was exactly the same: if we experiment in a separate namespace, the native implementation can change without breaking any existing deployed experiments!

But remember, humans want to use the native feature when it’s there. And they don’t want to go back and edit their code when that happens. So what do they do? They use both! Even if the native feature has no implementations yet, pre-emptively.

We know exactly how this plays out, because it already has: stylesheets everywhere declared -webkit-border-radius with an unprefixed border-radius right below it — before any browser shipped the unprefixed property, and before its syntax was final.

So authors get worse DX, and web standards get no more design flexibility. Everybody loses.

Is dropping feature detection the solution?

As another attempt to mitigate the issues, some have started recommending polyfills that skip feature detection entirely and always use the fallback implementation, even when the native feature exists.

This is extremely wasteful. Polyfills add weight, are typically slower than native implementations, less accessible, less i18nclusive, and rarely handle edge cases. As their name implies, they are meant to temporarily cover a gap. They were never meant to be a long-term solution. The whole point is planned obsolescence: they eventually become dormant, even in a codebase that is no longer actively maintained. Feature detection and conditional loading are essential for that to work.

Authors accept these costs because they are temporary: every browser update quietly moves more of their users onto the native implementation, until the polyfill fades into a no-op. Remove feature detection, and the costs become permanent. Every user pays the download forever, and no user ever gets the native implementation’s performance, accessibility, or i18n — even when it’s sitting right there in their browser.

This approach does preserve the advantages of a standardized API, but at what cost? It trades away real, tangible benefits, felt by every user of the Web, to prevent a rare, largely theoretical risk. Every economist would be pulling their hair out at this cost-benefit!

Are ponyfills the solution?

Ponyfills, as originally envisioned by Sindre Sorhus, are basically userland libraries that closely track the native API, but do not modify the global environment and may intentionally diverge from the spec.

They are often suggested as a better alternative to polyfills.

For example, a polyfill for RegExp.escape() might look like this:

if (!RegExp.escape) {
	RegExp.escape = function (s) {
		return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
	};
}

Whereas a ponyfill might be:

export function regexpEscape(value) {
	return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}

Note that this does not use the native implementation at all. It is not meant to be removed later. Its link to the native API is purely psychological.

I can see ponyfills being helpful for iterating on and getting feedback on an API while the standard is still being developed, or even to motivate a new proposal. But then again, so are userland libraries.

But for a mature feature, that has shipped in at least one browser, their appeal is much weaker.

They lack all strengths of polyfills:

  • They don’t use the native implementation, even when it exists.
  • They cannot be removed without refactoring
  • Without a standardized API, a ponyfill cannot be swapped for another without further refactoring.
  • They introduce a new userland dependency that needs to be evaluated, learned, documented, and maintained, just the same as if no standard existed at all.

IMO ponyfills are just userland libraries with better marketing.

Even their only advantage, not modifying the global environment and thus not trampling on the spec, is typically negated by actual usage: as a sort of …deconstructed polyfill.

See this post where the author is using a ponyfill for Number.MAX_SAFE_INTEGER as part of a makeshift polyfill:

const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || require('number-max-safe-integer');

This is the norm, not some lone author failing to grok the concept of ponyfills. In fact, many people would call something like this a ponyfill as well:

export function regexpEscape(value) {
	if (RegExp.escape) {
		return RegExp.escape(value);
	}

	return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}

This combines the disadvantages of both approaches, while getting you the benefits of neither!

In the end, the usage hasn’t changed, because the human need hasn’t changed.

Do polyfills discourage native implementations?

Stephen: […] polyfills can reduce the need for all browsers to implement something in a timely fashion.

Do they?

Yes, the existence of high-quality, lightweight polyfills can reduce the urgency for browsers to be the last to implement. But even then, the pressure never drops to zero: polyfills are slower and heavier than native implementations, and it’s the lagging browser’s own users who feel the difference. Without polyfills, authors wouldn’t use the feature at all — every browser would be equally fast at not supporting it, and the laggard could drag its feet indefinitely, consequence-free.

More importantly though, being last is not what’s critical for the Web’s evolution.

Check out my specs page. What is the average time from spec to first implementation, from that to the next, and from that to the last?

Milestone Proposals Mean time Median time
Spec → first implementation 9 1y 9m 7m 1d
First → second implementation 10 5m 10d 3m 5d
Second → last implementation 8 6m 14d 4m

The first implementation is the hardest.

A Web platform without polyfills would be a stagnant platform.

What is the motivation for a browser to be the first to implement if authors cannot use the feature until all others implement it as well? Would you sink millions of dollars of engineering time into something your competitors can render moot, by means of simply …doing nothing?

We cannot A/B test reality, so this is purely a thought experiment, but I think if polyfills, fallbacks, and progressive enhancement suddenly disappeared, it would slightly increase motivation for those shipping last, but would significantly reduce motivation for shipping first. And since nobody can be last without someone else being first, a Web platform without polyfills would be a stagnant platform.

Additionally, often the biggest blocker in getting browsers to implement new features is demonstrating developer demand. A popular polyfill does that beautifully.

In fact, there is already plenty of precedent that if a feature cannot be used conditionally, browsers are reluctant to implement it. For example, decorators consistently top the list of missing JS features, but because JS syntax cannot be reasonably polyfilled, they are nontrivial to implement, and they are so widely used via transpilers, no browser has shipped them. “Let them use build tools” seems to be the general unspoken consensus.

Polyfills only get in the way when the standards process fails

I did some digging; Anne’s view traces back to a 2025 whatwg/html discussion where an API around scoped custom element registries had to be renamed due to conflicts with two existing polyfills that implemented a different behavior (emphasis mine):

We have prototyped a solution that seems to work and preserves the API pretty much as-is (still unfortunate though; please stop polyfilling and deploying polyfills)

To be fair, the underlying concern is real, so let me steelman it. Once a library squatting a proposed API name becomes popular enough, its exact behavior — bugs and all — becomes a web compat constraint. Standards groups then face a choice between adopting the library’s semantics or breaking deployed sites, and sometimes the only way out is renaming or redesigning the native feature, which is what happened here. That is a real cost, borne by the very people designing the platform.

But let’s be clear: none of the libraries that caused this problem was actually a polyfill, since there was no standardized API to polyfill.

At worst, they were naughty userland libraries, much like MooTools’ Array.prototype.flatten() that caused the smooshgate fiasco. At best, they were speculative polyfills (aka prollyfills) — an imagined API occupying the same namespace as a future builtin so authors can experiment with an emerging standard. Prollyfills are (rightly) more controversial, and not what this post is about.

Assigning blame to polyfills is like blaming car accidents on the ambulances that show up on the scene.

But when you examine the failure cases more closely, they all have something in common: In every single one, standards groups and/or browsers failed to react to a strong user need in a timely fashion.

Assigning blame to polyfills is like blaming car accidents on the ambulances that show up on the scene. A popular polyfill is a consequence. Polyfills should never become too popular in the first place: the feature should be widely implemented by then!

If a polyfill (or prollyfill) becomes so popular that it can create a compat problem, that is a symptom that a pervasive user need went unmet for too long. Whether it’s a polyfill or a prollyfill only changes which entity failed to react in time.

And even in the failure cases, consider the counterfactual. When a prollyfill constrains the design space, the damage is a worse name or a compromised API shape — bounded, and known before shipping. When an API ships without real-world validation, the damage is unbounded, and only discovered once the design is frozen into the platform by web compat. Remember AppCache? It shipped natively with no userland trial run, turned out to be fundamentally wrong, and took a decade to deprecate and replace with Service Workers. A prollyfill that surfaces design problems while the spec can still change is far cheaper than deploying the wrong API.

Developers don’t use polyfills in vain. Every dependency has a cost. If we see a polyfill becoming wildly popular, that should be a signal for urgent prioritization, not a reason to complain that authors are naughty.

Instead of blaming the user (“please stop polyfilling and deploying polyfills”), we should be doing a post-mortem on how to avoid such process failures in the future.

“If one user gets it wrong, it might be them. If two users get it wrong, it’s definitely you” — Ancient UX proverb[2]

When web platform design follows the priority of constituencies, and prioritizes end-user and author needs above implementors and standards authors, the failure cases are practically nonexistent, even when polyfills jump the gun and ship too early.

The WHATWG process invites these failures

Why did scoped registries take so long to ship? The web components community had been asking for years!

Part of this is that the WHATWG process is designed to be reactive rather than proactive. Even if there is a strong, demonstrated author need, WHATWG will refuse to flesh out a feature until at least two implementors express interest in implementing it. “needs implementer interest” is where so many good ideas go to die.

This made sense when WHATWG was founded as a reaction to the increasingly academic W3C HTML Working Group, which had been designing XHTML 2 in a vacuum, speccing features that no browser was willing to implement.

But having spent 15 years in the CSS WG and having proposed and/or helped drive several features to Baseline, I cannot imagine gating spec development on implementor interest. That’s putting the cart before the horse!

Demonstrating developer need is exactly what drives implementor interest in the first place! And that’s much easier to do with a feature that is actively being worked on.

For one, researching use cases and prior art to flesh out the feature often demonstrates author need in itself. But also, users have a lot of trouble expressing abstract pain points. It is much easier to point to an existing feature and say “I want browsers to support this” than to express a need for which no feature exists.

In a way, polyfills are to the web platform what user testing is to product design — and the prototype part isn’t even an analogy: a polyfill literally is a prototype of the feature. Real user feedback, without baking technical debt into the platform. One could even argue that browsers should be funding — or outright developing — these polyfills, precisely so they can gather this feedback before an API is frozen into the platform by web compat. Yes, there is some risk they may constrain the ergonomics of the eventual API — but if high-demand features actually ship at a reasonable pace, that risk shrinks dramatically.

Polyfills restore power balance in the ecosystem

Who remembers IE7.js? Or html5shiv?

For nearly a decade, IE was the boat anchor of the Web: dominant market share, no meaningful competition, and no incentive to implement anything new. Without polyfills, the rational strategy for many authors was to target IE and call it a day — and the rational strategy for every other browser would have been to stop investing in features nobody could use.

Instead, polyfills allowed authors to adopt modern standards years before IE supported them. That kept demand for standards alive, sustained pressure on IE, and gave end-users reasons to switch browsers. The fact that we were finally able to move away from IE6 and IE7 is in large part thanks to polyfills.

A browser lagging behind is not always a matter of will, either — release cadence matters. IE, and EdgeHTML after it, was bound to the Windows release schedule, just as Safari is tied to the macOS and iOS release trains today — a constraint the engineers working on these engines have no say in. A slow release train stretches exactly the gap that polyfills exist to cover: even once a feature ships, it reaches users in OS-update time, not browser-update time. If every engine could ship at the cadence of Chromium and Firefox, the need for polyfills would shrink significantly. Until then, polyfills are how authors deliver the benefits of native APIs — performance, accessibility, i18n — without being held hostage to the slowest release train.

Without polyfills, a single browser has undue power to hold back the Web.

Without polyfills, fallbacks, and progressive enhancement, a single browser has undue power to hold back the Web — whether by choice or by circumstance. I’m far more concerned about that than about the occasional smooshgate.

Polyfills make the Web faster, inclusive, and more robust

Native features are typically more performant, more accessible, more i18nclusive, and handle more edge cases than any userland implementation.

A userland library can cut corners, exclude locales, declare that a11y is out of scope, and fail to consider edge cases. A web standard cannot.

A polyfill inherits some of these limitations while it’s active, but unlike a userland library, it is graded against a spec: its target behavior has already been through accessibility and i18n review, so its gaps are well-defined, visible, and centrally fixable. A userland library gets to define its own bar.

Developers being able to use web features before wide availability is a win for the Web as a whole.

Can we stop trying to solve the wrong problem?

Cost-benefit analysis is a fundamental part of human decision-making.
We get in cars, even though there is a risk of accidents.
We go outside, even though we may catch a cold — or worse.
We swim, even though there is a small risk of drowning.

We weigh the extent of the risk, the probability of it happening, and the cost of mitigating it, against the extent and frequency of the benefits, and decide accordingly. We do this all the time, whether consciously or not.

When it comes to the Web, the benefits of polyfills are tangible and felt by everyone who develops for it. Historically, failure cases have been few, and generally have been mitigated well. Even smooshgate resulted in array.flat(), which to me is not obviously worse than array.flatten().

We are spending so much collective energy trying to mitigate a largely theoretical problem, that has only been a significant issue a handful of times in the 30+ years of the Web’s history. And yet, many are willing to sacrifice significant, tangible, far-reaching benefits to do so. This is an emotional reaction to a few high-profile incidents, not a rational cost-benefit tradeoff.

Instead of trying to eliminate polyfills, we should be more proactive in discovering and reacting to developer needs, so polyfills never become so popular that they threaten the design space of a native API.

Starting from polyfilling itself. [3]

Huge thanks to Greg Whitworth and Cassondra Roberts for reviewing an earlier draft of this post.


  1. Special-casing known offenders like radios and checkboxes of course. ↩︎

  2. No, not really, I made this up, but the takeaway is pretty established in HCI. ↩︎

  3. Stay tuned: in Part 2 I’ll discuss what gaps in the Web platform make it hard to write good polyfills today, and how this varies across HTML, CSS, and JS. ↩︎

Read the whole story
alvinashcraft
1 hour ago
reply
Pennsylvania, USA
Share this story
Delete

Google and Epic Cancel Settlement; Third-Party App Stores Coming To Google Play

1 Share
An anonymous reader quotes a report from Ars Technica: Big changes are coming to Android apps, but they're not the changes Google wanted. The settlement between Google and Epic that aimed to put to rest the companies' long-running antitrust battle is being withdrawn, and that means third-party app stores are coming to the Play Store. Google has confirmed that it will begin distributing rival app stores next week, setting the stage for competing platforms to take a bite out of Google's Android revenue stream. [...] Google and Epic were set to return to court on July 16 to argue in favor of the settlement. However, the writing may have been on the wall. In a recent expert analysis provided to the court, MIT economics professor Nancy Rose noted that the settlement was "unlikely to enable Google Play's potential competitors to overcome their long-standing network-effect disadvantage in a timely manner." With settlement approval looking increasingly unlikely, Epic and Google agreed this week to call the whole thing off. Here's how Google Trust and Reputation Communications Lead Dan Jackson explains the company's decision: "We've agreed with Epic to withdraw our motion to modify the US Court's injunction rather than prolonging this process which creates uncertainty for the ecosystem. This allows us to focus on executing our recently announced global business model evolution to deliver greater app store choice, lower prices, and more opportunities for developers and users. We remain committed to maintaining Android's industry-leading security and fostering a competitive ecosystem where every app store and developer has the freedom to compete. In parallel, we continue to comply with the US Court's injunction." In a brief filing (PDF), Google's legal team informs the court that Google is prepared to begin distributing third-party app stores in Google Play on July 22. Under the terms of Judge Donato's original injunction, these stores will have access to the full catalog of Google Play apps by default. Developers will have the option to opt out of distribution in these stores, and Google has a support page explaining how to do so. Google also has documentation on how app stores can get access to the Google Play catalog. It won't be mirroring those apps in any shady storefront that asks. The court has allowed Google to charge reasonable fees to cover its security and compliance review of third-party stores, which will be $5,000 per year. Google will also require approved stores to block malware, respect intellectual property, and include mechanisms to update and uninstall apps. App stores can be removed from the program if more than 1 percent of attempted app installs appear to be malware or unwanted software. It's unclear if there will be separate, possibly more stringent requirements for storefront distribution in the Play Store. However, Google is prohibited from unreasonably blocking third-party store clients uploaded to Google Play. The changes Google has announced under the Epic agreement will proceed for now. That means Registered App Stores will happen globally, but they will probably only appear in the Play Store for US users. Google hasn't specified if there will be any differences in the features available to the stores downloaded from Play versus registered stores.

Read more of this story at Slashdot.

Read the whole story
alvinashcraft
2 hours ago
reply
Pennsylvania, USA
Share this story
Delete

Building Offline-First iOS Applications with Local Data Storage

1 Share

Offline-first behavior on iOS is not a cache toggle. It is a persistence decision that makes the device store the place where screens read, edits land, and state survives launch interruptions, suspension, and connectivity loss. Apple describes Core Data as a framework for saving permanent data for offline use on a single device, while SwiftData organizes persistent models around a ModelContainer and ModelContext that manage storage and lifecycle. Once that local layer becomes authoritative, the network stops being a prerequisite for ordinary interaction and becomes a synchronization transport instead. 

Local State Defines Availability

In practice, that means views should render from disk-backed state, not straight from requests. The broader offline-first pattern formalizes the local data source as the canonical read path, and Apple’s history APIs reinforce the same idea by tracking changes over time so that later reconciliation can be incremental rather than a full refresh. SwiftData History, for example, records ordered transactions and changes, which is exactly the raw material needed for server sync and extension-driven updates. 

Read the whole story
alvinashcraft
2 hours ago
reply
Pennsylvania, USA
Share this story
Delete

GitHub for Beginners: Your roadmap to mastering the GitHub essentials

1 Share

Everyone starts somewhere. Whether you’re writing your very first line of code or you’ve been building for years and never fully learned the tools underneath, this guide is your on-ramp.

This is the entire GitHub for Beginners series distilled into one holistic story—a detailed path that takes you from “what even is a repository?” all the way to collaborating on real projects and contributing to open source.

Read it top to bottom, and you’ll have a complete model of how modern software gets built on GitHub. Jump to any section, and you’ll find a self-contained answer. Let’s dive in.

Part 1: Get your bearings

1. What is version control (and why does it matter)?

Version control is a system that tracks changes to your files over time, and Git is the most widely used version control system in the world.

If you’ve ever saved brand_guide_v2, brand_guide_final, and brand_guide_FINAL_actually, you’ve already felt the problem that version control solves. Git records every change you make, so you can see what changed, when, and why. If you need to go back to an earlier version, it can handle that, too. You never need a folder full of “final” files again.

Git works through three zones: your working directory (where you edit), the staging area (where you review what’s ready), and the local repository (where your saved history lives). Three commands move work between them (i.e., git status, git add, and git commit) and you’ll use them so often they become muscle memory.

Read more: What is Git? Our beginner’s guide to version control

💡 Tip: When someone says “push your code,” they mean you should use Git to upload your local commits to GitHub.

2. How do I set up and secure my GitHub account?

Your GitHub account is your developer identity. You should make sure it’s well protected.

Turning on two-factor authentication (2FA) adds a second layer of protection that keeps your account safe even if your password is stolen. Passwords alone are vulnerable to phishing and reuse, so enable 2FA from Settings → Password and authentication.

While you’re here, give yourself a profile README. This is a living portfolio of your skills, projects, and interests. Create a public repository with the same name as your username, add a README, and whatever you write shows up on your profile page.

Read more: Beginner’s guide to GitHub: Setting up and securing your profile

💡 Tip: Download your recovery codes and store them in a password manager. They’re your only way back in if you lose your device.

3. Which Git commands do I actually need?

A small set of Git commands covers the daily workflow of nearly every developer.

The commands you want to become familiar with are .config, init, clone, add, commit, push, pull, branch, and switch.

You don’t need to memorize all of Git. Here are the ones you can use to get started:

Command What it does 
git config –global user.name “…” Set the name attached to your commits 
git init Turn the current folder into a Git repository 
git clone <url> Make a local copy of a remote repository 
git status See what’s changed in your local environment and what’s staged 
git add . Stage all your changes for the next commit 
git commit -m “message” Save a snapshot of your staged changes 
git switch -c <branch> Create a new branch and switch to it 
git push Upload your local commits to GitHub 
git pull Download and merge the latest changes from GitHub 
git merge <branch> Integrate another branch into your current one 

Read more: Top 12 Git commands every developer must know

Part 2: Build your first project

4. How do I create my first repository?

A repository (or “repo”) is a project folder that tracks changes, stores history, and lets multiple people seamlessly work together.

This is your project’s home base. Start from your dashboard, the page you land on when you sign in to github.com, which shows your repositories and activity feed.

  • Click the green New button
  • Give your repo a name
  • Choose public or private
  • Check the box to add a README. This is the first thing visitors see and should act as the front door to your project.

That’s it! You have a repository. You can optionally add a .gitignore to keep junk files out of version control and a license to tell others what they’re allowed to do with your code.

What’s a .gitignore for? As you work, your project folder fills up with files you never actually wrote. These are things your computer or tools automatically create (e.g. system files, folders of downloaded dependencies, temporary build output). You don’t want to track or share those, so a .gitignore file lists them and tells Git to leave them alone. It keeps your repository clean and focused on the code that actually matters.

Read more: Beginner’s guide to GitHub repositories: How to create your first repo

5. What is Markdown and how do I use it?

Markdown is a lightweight language for formatting plain text. It’s how you write READMEs, issues, pull requests, and comments across GitHub.

Markdown turns simple symbols into clean formatting. A few keystrokes give you documentation that’s a pleasure to read, which can make all the difference. You can use Markdown syntax, along with some HTML tags, to format your writing on GitHub.

Read more: GitHub for Beginners: Getting started with Markdown

6. What is the GitHub flow?

The GitHub flow is the repeatable loop for safely adding work to a shared progress: branch, commit, push, open a pull request, merge.

Here’s the rhythm you’ll keep on repeating:

  1. Clone the repo to your machine
  2. Create a branch for your work
  3. Make changes
  4. Commit them
  5. Push them to GitHub
  6. Open a pull request.

You can collaborate on anything you store in a repository. For example, imagine your team keeps its reusable AI prompts in a shared repo. You rework the prompt to improve the output. You make that change on a branch, open a pull request, and a colleague checks the new output before it’s approved. Once it’s merged, the next teammate who refreshes the repo is automatically writing from the improved prompt. There’s no need to send out an announcement to use the new prompt and no attachment drifting around inboxes. It’s the same branch-review-merge loop developers use, applied to words instead of code.

Read more: Beginner’s guide to GitHub: Adding code to your repository

💡 Tip: Give branches descriptive names like fix-login-bug or add-dark-mode so everyone knows what they’re for at a glance.

Part 3: Collaborate with other people

7. What is a pull request?

A pull request is a proposal to merge a set of changes from one branch into another, with a built-in space for teammates to review and discuss.

A pull request is where collaboration happens. It shows a visual diff of exactly what you changed and gives reviewers a place to comment . Write a clear title and description, link any related issues, and review your own pull request first to catch obvious mistakes.

💡 Tip: Smaller pull requests are easier and faster to review and merge, provide less room to introduce bugs, and provide a clearer history of changes.

Read more: Beginner’s guide to GitHub: Creating a pull request

8. How do I merge a pull request and fix a merge conflict?

Merging integrates reviewed changes into your target branch. A merge conflict is simply Git asking for your help when two changes touch the same lines of code and it doesn’t know how to integrate both changes at the same time.

Most merges are one green button: click Merge pull request, confirm, done. 🎉 Sometimes two branches edit the same lines of a file and Git can’t decide which version wins. In this case, GitHub marks the conflicting sections. You use the browser editor or VS Code to choose what to keep, mark it resolved, and merge. With a little practice, it feels as natural as any other push.

Read more: Beginner’s guide to GitHub: Merging a pull request

9. What are GitHub Issues and Projects?

Issues track individual tasks, bugs, and ideas, while projects organize those issues into a visual board so nothing slips through the cracks.

Issues are shared, trackable notes. Each one is a task, bug, or idea you can assign, label, and discuss. Projects pull those issues onto a Kanban-style board so you can see the status of all the issues at a glance. Here’s a small piece of magic that ties it all together. Every issue gets its own number. You’ll see it after the title as a hashtag and then a number (e.g., Let’s call a sample issue The answer to everything #42). When you open a pull request to fix that issue, you can type a closing keyword into the pull request description (e.g., Closes #42, Fixes #42, or Resolves #42).

GitHub recognizes that phrase as a link between the two: the pull request and the issue now reference each other. Then, the moment that pull request is merged, GitHub automatically marks issue #42 as closed for you. If the issue is on a project board, it slides over to the “Done” column on its own. It’s a simple habit that keeps your code changes and your task tracking in sync without any extra effort.

Read more: GitHub for Beginners: Getting started with GitHub Issues and Projects

Part 4: Level up your projects

10. What is GitHub Actions?

GitHub Actions is a CI/CD and automation platform built into GitHub that automatically runs tasks (e.g., tests, deployments, labeling) when events happen in your repo.

Once your project is moving, use GitHub Actions to let GitHub do the repetitive work. Write a workflow as a YAML file in .github/workflows/, tell it what event should trigger it, and define the steps to run. From then on, GitHub follows those steps on its own.

Read more: GitHub for Beginners: Getting started with GitHub Actions

11. How do I publish a website for free?

Got a portfolio, a project page, or documentation? GitHub Pages can host it for free at username.github.io/repo-name with no servers to manage. Enable it from Settings → Pages, choose to deploy from a branch, and you’re live in minutes. Even private repositories can publish a public site. This is great for showcasing work with code you’d rather keep to yourself.

Read more: GitHub for Beginners: Getting started with GitHub Pages

💡 Tip: Use Pages to promote your projects, share what you’re building, and grow your portfolio.

12. How do I secure my code on GitHub?

Security isn’t a final step; it’s a habit. GitHub Advanced Security is a built-in suite that automatically finds and helps you fix vulnerabilities. It includes secret scanning, Dependabot, and CodeQL code scanning, and it’s free for public repositories.

Secret scanning catches API keys you accidentally commit. Dependabot watches your dependencies for known vulnerabilities and opens pull requests to update them. CodeQL analyzes how data flows through your code to spot risky patterns and explains how to fix what it finds. Turn it all on from your repository settings.

Read more: GitHub for Beginners: Getting started with GitHub security

💡 Tip: You inherit any risk from a library the moment you import it into your project, even though you didn’t write the vulnerable code yourself.

13. How do I contribute to open source?

Open source software has freely available code that anyone can study and improve, and GitHub is its home.

How do you find the perfect project to contribute to? First, look for projects with a clear README, a CONTRIBUTING.md, an open source license, and issues tagged good first issue. That label is maintainers’ way of waving beginners in.

Contributing to real projects is one of the fastest ways to grow, and a fork makes it safe to do so. A fork is your own personal copy of someone else’s repository where you can experiment freely, then propose your changes back with a pull request.

So how is a fork different from a branch? A branch is a parallel workspace inside a repository you already have permission to change. A fork copies an entire repository into your account, which is what you need when you don’t have permission to edit the original (like most open source projects). A common workflow combines both: you fork the project, create a branch in your fork for your changes, and then open a pull request back to the original.

Read more: GitHub for Beginners: Getting started with open source contributions

Still have questions? Check out our most commonly asked questions and watch the full series of GitHub for Beginners on YouTube. You can also get started with GitHub Docs.

The post GitHub for Beginners: Your roadmap to mastering the GitHub essentials appeared first on The GitHub Blog.

Read the whole story
alvinashcraft
3 hours ago
reply
Pennsylvania, USA
Share this story
Delete

Don’t Neglect the Operational Groundwork

1 Share

Autonomous agents are moving faster than the field’s ability to govern them, and catching up requires more than better prompts or bigger sandboxes. At O’Reilly’s recent AI Superstream focused on OpenClaw and the broader ecosystem of locally run and self-hosted AI agents, five speakers, each working at a different layer of the stack, explored patterns for addressing many of the challenges developers will face implementing an agentic system, from risky third-party extensions, hallucinated compliance, and spaghetti codebases only an AI can read to cost overruns from misconfigured models, supply chain attacks, and worse.

As host Alistair Croll noted during the event, we can get better and better with nondeterministic technology, but we’ll never be 100% certain it’s working. The harder it gets to inspect what’s running, the more the governance layer matters. That work is unglamorous, mostly invisible to end users, and probably more important than any model capability improvement shipping this quarter.

Secure the action your agent takes at the execution layer

Eran Sandler, founder of Canyon Road and the team behind AgentSH, opened his talk by running through a list of common ways agents can be compromised, including prompt injection, malicious files, unsafe tools, compromised packages, installed skills, and model mistakes. Most AI security thinking focuses on the first one and ignores the other five, but “guarding the input box does not guard the action,” Eran explained.

His advice is enforcement at the execution layer, the boundary between the agent’s intent and the operating system that carries it out. Container isolation limits blast radius, Eran acknowledged, but it doesn’t make decisions. “Walls keep things in. They don’t make judgment calls.”

To illustrate the point, he installed a simulated malicious package, the kind that could arrive bundled with a routine task like “build me a sales prediction model.” Then he queried AgentSH’s deny log and pulled up a list of what actually happened while the agent was busy congratulating itself, including an attempted skill mutation, a blocked call to an external domain, and reads of .env secrets and SSH keys. “Transcripts might lie,” he says. “Models hallucinate compliance all the time. You can tell them in your rules files, please don’t touch this file, and they’ll still do it.” Without execution-layer controls, Eran said, “you’re hoping the model behaves. With it, you can prove what happened.”

Skills are a supply chain risk, and most people aren’t reading them

A recent audit of ClawHub found over 900 malicious skills, which at the time meant nearly 20% of total packages were risky. Most of these skills look professional, with documentation, high download counts, and user ratings. Kesha Williams, Keysoft founder and head of AI, audited one live—a typosquat of the real ClawHub CLI tool. (It used all lowercase where the legitimate package uses camel case.) The skill had more than 8,000 downloads before it was removed.

Here’s how it worked. The prerequisites section asked users to install a fake dependency called open-claw-core and then referenced a password-protected zip file from GitHub (the password was “openclaw”) specifically to bypass automated scanning. For macOS, it echoed a legitimate-looking install command that actually decoded a base64 string and piped it to bash.

“It looks like a skill you could actually need and use,” Kesha pointed out. “But once you really dig in and read what it’s actually doing, that is not a skill you want to install on your system.”

A good defense starts with two things most users skip: reading the skill Markdown file before installing it and configuring the toolsDeny section of the OpenClaw config to limit a skill’s access. If a summarizer skill needs exec, that’s suspicious, Kesha said. Block it. She also showed how to restrict the 50-plus bundled skills that ship with OpenClaw, most of which users haven’t reviewed. The skillsAllowed configuration lets you determine exactly which bundled skills stay active.

The open source software supply chain has always had trust problems, but the friction of traditional package management meant you at least needed technical knowledge to participate. Skills written in Markdown and installed with a single command lower that bar significantly. “Right now,” Kesha explained, the best policy for anyone extending their agent with third-party tools is to “keep a human in the loop and do your own due diligence.”

Operational hygiene failures are more common than adversarial attacks

Most OpenClaw risk is the result of operational hygiene failures that happen in the first hour after installation, argues Erik Hanchett, a developer advocate at AWS and the creator of the Program with Erik channel. There are thousands of OpenClaw instances currently exposed on the public internet because users didn’t check the gateway bind mode after setup. As Erik demonstrated, the default should be loopback (localhost), but a user who deploys on a VPS and sets the gateway to LAN may inadvertently expose their instance. The fix takes two minutes, but most people never do it.

That’s recommendation one on Erik’s five-point checklist. The others include pinning to a stable version rather than always updating to the latest (a crowdsourced stability tracker at Is It Stable? can help), configuring fallback models to avoid burning through expensive frontier tokens on routine tasks, writing a real SOUL.md rather than rushing through the onboarding prompts, and setting up backup of workspace files to a private GitHub repo before anything breaks. He also shared tips on context management, such as using /new to start fresh sessions rather than accumulating one long conversation, and using /compact when sessions grow large enough to affect performance, are the kind of operational detail that doesn’t appear in documentation but matters in daily use.

The Docker and Kubernetes eras produced the same pattern: powerful infrastructure technology deployed by enthusiastic early adopters who hadn’t always thought through the operational defaults. The problems Erik described—exposed dashboards, runaway token costs, and memory that resets unexpectedly—are the most common reasons people abandon agentic tools after a few weeks. The good news is they’re eminently fixable with the right guidance.

In regulated environments, plausibility isn’t accuracy

Ari Joury, CEO of Wangari Global, is working to solve the question that most enterprises experimenting with agents are probably asking themselves: How should we handle autonomous agents that operate in environments where being wrong has legal consequences?

Wangari Global builds financial reporting automation for institutional clients. However, LLMs are optimized for plausibility, not accuracy. In financial services, that gap is a compliance risk. Ari gave an example of AI output that sounded correct. . .until a client read it and “told [the company] it was complete nonsense.”

In response, Ari and his team stopped treating the AI as a magic box and engineered a framework to ensure veracity. Numbers are now calculated with hard-coded deterministic code, then agents verify the math for plausibility. A separate agentic layer generates commentary, and another critiques it. Humans approve or reject the output, and every rejection becomes a training signal for future iterations.

Human input is the only thing that prevents AI slop at scale

Kyle Balmer closed things out with a demonstration of his agent-assisted process for content production for his AI with Kyle channel, addressing the economic incentive structure driving agent adoption outside software development. While he’s found autonomous agents to be economically transformative, the system only works if you design human input and review into it deliberately, which Kyle illustrated in a workflow that distinguished between automated and human processes.

His daily workflow converts a one-hour livestream into 20 to 30 derivative assets, including a newsletter, five to eight short-form videos, carousels, and a long-form YouTube video. The whole system runs on roughly $200 a month, and Kyle estimates that translates to roughly $1,000–$2,000 worth of potential customers entering his funnel daily.

The process is not fully automated: Kyle injects himself into the process at various steps throughout. He chooses the topic. He records voice notes with his actual opinions. He delivers the livestream pulling those thoughts together into clear arguments. He rewrites the AI-generated newsletter draft using his own voice. He records the short-form video scripts himself rather than using an AI avatar. The AI handles research, briefing, slide generation, script drafting, and the feedback loop that improves output over time, but the human provides the signal.

“I have tested with fully automated AI content,” he says. “It does not work. It is slop. And people know it’s slop.”



Read the whole story
alvinashcraft
3 hours ago
reply
Pennsylvania, USA
Share this story
Delete

Handling Alt Text in a Linked Image

1 Share

A little nuance I ran into. Say you have a regular ol’ image:

<img src="some/avatar.webp" alt="Photo of so and so looking directly and camera with a toothy smile.">

Cool. Now say you want to link that image somewhere:

<a href="author/so-and-so/">
  <img src="some/avatar.webp" alt="Photo of so and so looking directly and camera with a toothy smile.">
</a>

Double cool. But now I want unsighted visitors to know where that link goes. I suppose I could do the classic visually-hidden text thing to announce it without visually presenting it.

<a href="author/so-and-so/">
  <img src="some/avatar.webp" alt="Photo of so and so looking directly and camera with a toothy smile.">
  <span class="visually-hidden">Click to read this author's posts.">
</a>

That seems correct, but I’m hesitant at the same time because now we have an announced link, followed by an announced image, followed by hidden directive text.

Another, perhaps simpler approach? Put the directive text in the alt:

<a href="author/so-and-so/">
  <img src="some/avatar.webp" alt="Photo of so and so looking directly and camera with a toothy smile. Click to read posts.">
</a>

But I’m hesitant about that. I think alternative text is only supposed to describe the image. Is adding functional context an anti-pattern?

Genuine questions: Is one approach better than the other? Is there another approach I’m simply missing? Am I over-thinking this?

Read the whole story
alvinashcraft
3 hours ago
reply
Pennsylvania, USA
Share this story
Delete
Next Page of Stories