DEV.to 팔로워, 이제 GitHub 프로필에서 실시간으로 뽐내세요! ✨
2026. 9. 27.
DEV.to 팔로워, 이제 GitHub 프로필에서 실시간으로 뽐내세요! ✨
DEV.to에서 쌓아 올린 팔로워 수를 GitHub 프로필에 자랑스럽게 걸어두고 싶은 개발자분들을 위해 준비했습니다. 길고 지루한 설명은 접어두고, 바로 본론으로 들어가죠. 이 작은 프로젝트는 여러분의 DEV.to 팔로워 수를 GitHub 프로필에 자동으로 업데이트해주는 스크립트입니다.
<hr>작년 이맘때쯤, 재미 삼아 시작했던 프로젝트였는데, 여느 사이드 프로젝트가 그렇듯 흐지부지 잊히고 말았습니다. 하지만 저를 끊임없이 괴롭히는 한 가지가 있었죠. 매일 아침 메일함에 날아드는 "Github Actions 실행 실패" 알림! 😂
처음에는 그냥 다 지워버릴까 고민도 했습니다. 하지만 왠지 모르게 자존심이 상하더군요. '이 정도는 내가 충분히 고칠 수 있는데?' 하는 오기가 발동했습니다. 결국 어느 날, 지긋지긋한 메일을 더 이상 참을 수 없어 제대로 붙잡고 뜯어고치기 시작했죠. API 호출 방식을 조금 수정하고, 불필요하게 주석 처리된 코드를 과감히 삭제했더니, 흐릿했던 그림이 선명해지기 시작했습니다. 제가 실무에서 이런 종류의 잊혀진 코드를 디버깅해 봤을 때, 초기 설계의 불명확함이나 불필요한 레거시 코드가 얼마나 많은 시간을 잡아먹는지 잘 압니다. 이번에도 군더더기를 쳐내니 훨씬 명쾌해지더군요.
저처럼 1년 내내 실패 알림에 시달리지 않도록, 제가 완성한 GitHub Actions 파일 전체를 공유합니다. 제 GitHub 리포지토리에서 성공적으로 343번째 실행을 마친 모습이 그 증거입니다. 드디어 첫 성공을 맛본 순간이었죠!

여러분들이 가장 기다리던 부분, 바로 작동하는 코드입니다.
핵심: GitHub Actions YAML 설정
이 YAML 파일은 매일 자정(UTC 기준)에 DEV.to 팔로워 수를 확인하고, 변경 사항이 있다면 README.md를 업데이트한 후 자동으로 커밋하고 푸시합니다.
name: Update DEV.to Followers Count
on:
schedule:
# 매일 자정(UTC)에 실행
- cron: '0 0 * * *'
workflow_dispatch: # 수동 실행을 위한 트리거
permissions:
contents: write # README.md 파일을 업데이트하기 위한 쓰기 권한
jobs:
update-count:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '22' # Node.js 22 버전 사용
- name: Run the update script
env:
DEVTO_API_KEY: ${{ secrets.DEVTO_API_KEY }} # DEV.to API 키 (GitHub Secrets에 저장)
DEVTO_USERNAME: annavi11arrea1 # DEV.to 사용자명
run: node update_script.js # 팔로워 수를 가져오고 README를 업데이트하는 스크립트 실행
- name: Commit updated README
run: |
if git diff --quiet -- README.md; then
echo "Follower count has not changed."
exit 0
fi
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add README.md
git commit -m "Update DEV.to follower count"
git push
🚨 중요 사항 몇 가지!
- API 키 보안:
DEVTO_API_KEY는 절대로 코드에 하드코딩하지 마세요! GitHub Secrets에 저장해서 환경 변수로 불러오는 것이 가장 안전합니다. 이렇게 해야 DEV.to API를 무료로 계속 이용할 수 있습니다. 🦋 - README.md 위치 지정:
README.md파일 내에서 팔로워 수가 출력될 위치를 지정해야 합니다. 스크립트는 아래와 같은 특별한 태그를 찾아 내용을 업데이트합니다. (아래 태그 전체를 확인하려면 스크롤하세요._start_와_end_태그가 있습니다.)
이 태그 사이에 현재 팔로워 수가 자동으로 삽입될 겁니다. 이 태그를 반드시<!-- DEVTO-FOLLOWERS-COUNT:START -->**34996** DEV.to followers<!-- DEVTO-FOLLOWERS-COUNT:END -->README.md에 포함시켜 주세요.
이게 정말 작동한다는 사실에 너무 기쁩니다! 팔로워 수를 자랑하려는 의도라기보다는, 다른 프로필에서도 조용히(?) 나의 성장 지표를 뽐내고 싶은 개발자들의 마음을 대변하고 싶었거든요. 하하.
가장 중요했던 변경 사항은 contents: write 권한을 부여하고, 작업이 성공적으로 완료되면 README.md 변경 사항이 자동으로 푸시되도록 설정한 것입니다. 실제 업데이트가 반영되려면 이 두 가지가 핵심이죠. 문득, GitHub Actions로 또 어떤 자동화를 해볼 수 있을지 궁금해지네요. 제가 실무에서 이걸 써보니, CI/CD 파이프라인 구축은 물론이고, 이런 식의 간단한 데이터 동기화나 리포트 자동 생성 같은 소소하지만 확실한 만족감을 주는 자동화에도 엄청난 잠재력이 있다는 걸 깨달았습니다. 한번 맛들이면 헤어 나오기 힘든 매력이랄까요?
@fm 님의 지적 덕분에 이 작업을 마무리할 수 있었습니다. 이제 update_script.js 파일을 공개합니다. 😂
const fs = require("fs");
const https = require("https");
const DEVTO_API_KEY = process.env.DEVTO_API_KEY; // 환경 변수에서 DEV.to API 키 가져오기
const DEVTO_USERNAME = process.env.DEVTO_USERNAME || "annavi11arrea1"; // DEV.to 사용자명
const README_FILE = "README.md";
const START_MARKER = "<!-- DEVTO-FOLLOWERS-COUNT:START -->"; // 시작 마커
const END_MARKER = "<!-- DEVTO-FOLLOWERS-COUNT:END -->"; // 종료 마커
const USER_AGENT = "AnnaVi11arrea1-GitHub-Actions"; // API 요청 시 User-Agent
if (!DEVTO_API_KEY) {
throw new Error("Missing required DEVTO_API_KEY environment variable.");
}
const parseResponsePreview = (data) => {
const trimmed = data.trim();
return trimmed ? trimmed.slice(0, 500) : "<empty>";
};
// DEV.to API에서 JSON 데이터를 가져오는 함수
const fetchJson = (path) => {
const options = {
hostname: "dev.to",
port: 443,
path,
method: "GET",
headers: {
"api-key": DEVTO_API_KEY,
Accept: "application/vnd.forem.api-v1+json",
"User-Agent": USER_AGENT,
},
timeout: 15000, // 15초 타임아웃
};
return new Promise((resolve, reject) => {
const req = https.request(options, (res) => {
let data = "";
res.on("data", (chunk) => {
data += chunk;
});
res.on("end", () => {
if (res.statusCode !== 200) {
const preview = parseResponsePreview(data);
reject(
new Error(
`DEV.to API request failed (${res.statusCode} ${res.statusMessage || "Unknown"}). Response preview: ${preview}`
)
);
return;
}
try {
resolve(JSON.parse(data));
} catch (error) {
reject(new Error(`Failed to parse API response. Response data: ${data}`));
}
});
});
req.on("timeout", () => req.destroy(new Error("DEV.to API request timed out.")));
req.on("error", reject);
req.end();
});
};
// 팔로워 수를 가져오는 함수 (페이지네이션 처리)
const getFollowersCount = async () => {
const perPage = 1000;
let page = 1;
let totalCount = 0;
while (true) {
const followers = await fetchJson(
`/api/followers/users?page=${page}&per_page=${perPage}`
);
if (!Array.isArray(followers)) {
throw new Error("DEV.to followers endpoint returned an invalid response.");
}
totalCount += followers.length;
if (followers.length < perPage) { // 더 이상 팔로워가 없으면 종료
return totalCount;
}
page += 1;
}
};
// README.md 파일을 업데이트하는 함수
const updateReadme = async () => {
const count = await getFollowersCount(); // 현재 팔로워 수 가져오기
let readmeContent = fs.readFileSync(README_FILE, "utf8"); // README 파일 읽기
const newContent = `${START_MARKER}**${count}** DEV.to followers${END_MARKER}`; // 새로운 내용 생성
// 마커 사이의 내용을 새로운 팔로워 수로 교체
const regex = new RegExp(`${START_MARKER}[\\s\\S]*?${END_MARKER}`, "g");
readmeContent = readmeContent.replace(regex, newContent);
fs.writeFileSync(README_FILE, readmeContent); // README 파일 업데이트
console.log("README updated with new follower count:", count);
};
// 스크립트 실행
updateReadme().catch((error) => {
console.error(error);
process.exit(1);
});
원문: https://dev.to/annavi11arrea1/sharing-dev-followers-count-on-github-profile-bj3 수집일: 2026-09-27 02:07:34