ヘルプセンター

NewtからNILTOへの移行手順

2025年5月20日、ヘッドレスCMS「Newt(ニュート)」のサービス終了が発表されました。Newtのサービス終了により、多くのユーザー様が移行先を検討されていることと思います。本記事では、Newtからの移行先としてNILTOへスムーズに移行できる理由や料金プランの比較、NewtからNILTOへの移行手順について解説していきます。

※本記事でご案内している移行手順はNILTOのビジネスプラン以上で利用できるCSVインポート機能が必要となります。
14日間の無料トライアル期間を利用することで、ビジネスプランのCSVインポート機能を利用することができます。NILTOへ移行の際はぜひご利用ください。
無料トライアル期間中であれば、移行後にパーソナルプランに戻すことで費用は発生せず利用することができます。

NILTOへスムーズに移行できる理由

Newtユーザーが馴染みやすい階層構造

Newtはスペース、App、モデルという3階層の構造でコンテンツを管理しています。NILTOも同様に組織、スペース、モデルという3階層の構造をしています。このようにNewtとNILTOは近い階層構造をしているため、NewtユーザーにとってNILTOは適応しやすい設計となっています。

フロントエンドの移行がしやすいAPI設計

NILTOの Developer APIは、Newt APIとクエリパラメータの指定方法などに多くの共通点があります。特に検索や、フィルタリングといったデータ取得に関する指定方法が近いため移行しやすい設計となっています。

大規模組織向けの高度な運用要件に対応

NILTOはNewtと同様にエンタープライズ向けのプランをご用意しています。
組織、スペース、サブスペースによる柔軟なアカウント管理、権限設定に加え、シングルサインオン、2要素認証、監査ログ、IP制限、メディアファイルのランダム変更、ISMS認証(ISO/IEC 27001)など、高いセキュリティ要求にも対応可能です。

料金プランの比較

移行を検討する上で重要な要素のひとつが料金プランです。NewtとNILTOはどちらも無料プランから利用可能で、段階的に機能が開放されます。対象となる組織、チームの規模や、運用体制にとって適したプランが異なります。

個人向けのフリーのプラン

小規模サイト向けのプラン

高機能な中規模案件向けのプラン

高いセキュリティが求められる大企業向けのプラン

NewtからNILTOへの移行手順

移行手順に入る前の準備

アカウント登録

Googleアカウント、もしくはメールアドレスで認証してアカウントを作成します。
アカウント登録画面から登録してください。
パスワードの条件は以下になります。

  • 半角英数
  • 8文字以上
  • 大文字、小文字、数字を含む

メールアドレスによる確認手続き

入力が完了し登録へ進むと「確認メールが送信されました」と画面が切り替わります。
アカウント登録時に入力したメールアドレス宛にメール (noreply@nilto.com)からメールが届きますので、記載されているURLをクリックすると認証が完了します。

メールが届かない場合は、迷惑フォルダやプロモーションのフォルダに分けられている場合がありますので、ご確認ください。
また、メールアドレスが間違っていた場合は再度登録からお願いいたします。

組織の作成

組織の概念はこちらをご参照ください。
アカウントを作成し、再度「https://cms.nilto.com/」にアクセスすると組織とスペースを作成するダイアログが表示されます。
組織名・スペース名・コンテンツのメイン言語を設定したら右下の[作成]を押して完了します。
組織・スペース名は後から変更が可能です。

スペースへ移動

組織の作成が完了すると組織内のスペースへ切り替わります。
赤枠内の部分に「スペース名」が表示されます。

モデルの作成

コンテンツのひな形となるモデルを作成します。
サイドバーから「モデル」を選択して、モデルのページに移動します。
次にヘッダーの右上にある[+モデル作成]を選択します。
もしくはサイドバーの「モデル」の右に表示される[+]ですぐにモデルを作成することができます。

モデル名とLUIDに好きな値を入力し、[作成]をクリックします。
LUID設定が可能な条件は下記になります。
ただし先頭に使える文字は英小文字と数字のみです。

  • 英小文字
  • 数字
  • アンダースコア

↑画像の内容をニュース記事に変更

NILTO、Newt で以下のようなフィールドを持つ「ニュース記事」モデルを作成していると仮定します。

  • title: 記事タイトル
     テキスト → 1行テキスト
  • slug: スラッグ
     テキスト → 1行テキスト
  • body: 記事本文
     リッチテキスト or マークダウン → 複数行テキスト
  • category: (参照 - 別の「カテゴリ」モデルを参照)
     参照 → 参照
  • publishedAt: 公開日(Date)
     日付 → 日付
  • mainImage: メイン画像
     画像 → メディア
  • author: 著者(参照 - 別の「著者」モデルを参照)
     参照 → 参照

※チュートリアルでは、以下を入力しています。

  • モデル名:ニュース記事
  • モデルLUID:news

APIキーの確認

インポートしたコンテンツをAPI経由で取得する準備をします。
サイドバーの「スペース設定」からAPIキーのページへ移動します。
ドラフト権限付き(下書き+公開)のAPIキーを確認して控えておきます。

APIキーの詳細画面で行えることは以下の通りです。

  • APIキー名の編集
  • トークンの確認/コピー
  • 権限の付与/削除(コンテンツ・メディア)
  • APIキーの削除

移行手順に入る前の準備はこれで完了です。
続いて Newt からコンテンツをエクスポートする手順を説明します。

Newtからのコンテンツエクスポート手順

Newt でのコンテンツエクスポートは、下書きのコンテンツを含める場合はNewt API、公開コンテンツのみの場合は、CDN APIを利用をします。
今回は Newt API での例を説明します。

Newt API を利用したコンテンツエクスポート(Nodejs)

Nodejs での NewtAPI を利用したコンテンツエクスポートの手順を説明をします。

axios ライブラリのインストール

今回の例では axios ライブラリを使用します。プロジェクトディレクトリを作成し、その中でターミナルまたはコマンドプロンプトで以下のコマンドを実行してインストールします。

npm install axios

Newt API トークンの取得

Newt の管理画面から API トークンを取得してください。

Space UID、App UID、 Model UID の確認

エクスポートしたいコンテンツが含まれる App の UID と Model の UID を Newt の管理画面で確認してください。

Newt のコンテンツインポートと CSV エクスポートのコードの作成

プロジェクトディレクトリ上にexport_news.jsを作成します。実際のコードは以下になります。

const axios = require("axios");
const fs = require("fs");
const path = require("path");

// --- 設定項目 ---
const NEWT_SPACE_UID = "YOUR_SPACE_UID";    // ご自身のスペースUIDに置き換えてください
const NEWT_APP_UID = "YOUR_APP_UID_NEWS";   // ニュース記事のApp UIDに置き換えてください
const NEWT_MODEL_UID = "YOUR_MODEL_UID_ARTICLE"; // ニュース記事のModel UIDに置き換えてください
const NEWT_API_TOKEN = "YOUR_API_TOKEN";    // ご自身のAPIトークンに置き換えてください

// 出力ファイル名
const OUTPUT_CSV_FILE = `${NEWT_MODEL_UID}_export.csv`;

// APIエンドポイント
const API_BASE_URL = `https://${NEWT_SPACE_UID}.cdn.newt.so/v1/${NEWT_APP_UID}/${NEWT_MODEL_UID}`;

// --- ヘッダー ---
const headers = {
    "Authorization": `Bearer ${NEWT_API_TOKEN}`
};

// --- コンテンツ取得関数 ---
async function fetchAllNewsArticles() {
    console.log("ニュース記事の取得を開始します...");
    let allArticles = [];
    let skip = 0;
    const limit = 100; // 一度に取得する最大件数

    try {
        while (true) {
            const params = {
                skip: skip,
                limit: limit,
                // APIで取得するフィールドを選択 (パフォーマンス向上のため、必要なものだけに絞ることを推奨)
                // 例: title, slug, body, category, publishedAt, mainImage, _sys (作成日等)
                // select: "_id,title,slug,body,category,publishedAt,mainImage,_sys.createdAt",

                // ネストされたリレーションフィールドを展開して取得する場合 (depthで階層を指定)
                // category の name フィールドを取得したい場合など
                // depth: 2, // category.name を取得したいなら depth 2 (Model -> category -> name)
            };
            const response = await axios.get(API_BASE_URL, { headers, params });
            const articles = response.data.items || [];
            allArticles = allArticles.concat(articles);

            console.log(`${articles.length} 件の記事を取得しました。現在の合計: ${allArticles.length} 件`);

            if (articles.length < limit) {
                break;
            }
            skip += limit;
        }
    } catch (error) {
        console.error("APIリクエスト中にエラーが発生しました:", error.response ? error.response.data : error.message);
        return null;
    }

    console.log(`合計 ${allArticles.length} 件の記事を取得しました。`);
    return allArticles;
}


// --- CSVファイルへのエクスポート関数 ---
function exportToCsv(articles, filename) {
    if (!articles || articles.length === 0) {
        console.log("記事データが取得できなかったか空のため、CSVエクスポートをスキップします。");
        return;
    }

    console.log("CSVファイルへのエクスポートを開始します...");

    // CSVのヘッダーを定義 (ここにCSVに出力したいフィールド名を列挙)
    // リレーション先のフィールドや、整形が必要なフィールドは事前にデータを加工することを推奨
    const csvHeaders = [
        "_id",
        "title",
        "slug",
        "publishedAt",
        "category_name", // 例: categoryリレーションのnameフィールド
        "author_name",   // 例: authorリレーションのnameフィールド
        "mainImage_url", // 例: mainImageのURL
        "body_text",     // 例: body (RichText/HTML) からテキスト部分のみ抽出
        "tags_joined",   // 例: tags配列をカンマ区切り文字列に
        "_sys_createdAt",
        "_sys_updatedAt"
    ];
    let csvContent = csvHeaders.join(",") + "n";

    // 各記事データをCSVの行に変換
    articles.forEach(article => {
        // --- ここで記事データをCSVの各列に合わせて整形 ---
        // この整形処理は、実際のデータ構造とCSVの要件に合わせて調整してください。
        const rowData = {
            _id: article._id || "",
            title: article.title || "",
            slug: article.slug || "",
            publishedAt: article.publishedAt ? new Date(article.publishedAt).toLocaleDateString("ja-JP") : "",
            category_name: article.category && article.category.name ? article.category.name : (typeof article.category === "string" ? article.category : ""), // categoryがオブジェクトでnameを持つか、単なる文字列IDの場合
            author_name: article.author && article.author.fullName ? article.author.fullName : "", // authorリレーション先のfullNameフィールドを想定
            mainImage_url: article.mainImage && article.mainImage.src ? article.mainImage.src : "",
            body_text: article.body ? String(article.body).replace(/<[^>]+>/g, "").substring(0, 200) + "..." : "", // HTMLタグを除去し、最初の200文字 (簡易版)
            tags_joined: Array.isArray(article.tags) ? article.tags.map(tag => (typeof tag === "object" ? tag.name : tag)).join(" | ") : (article.tags || ""), // タグがオブジェクトの配列か文字列の配列か
            _sys_createdAt: article._sys && article._sys.createdAt ? new Date(article._sys.createdAt).toLocaleString("ja-JP") : "",
            _sys_updatedAt: article._sys && article._sys.updatedAt ? new Date(article._sys.updatedAt).toLocaleString("ja-JP") : "",
        };

        const row = csvHeaders.map(header => {
            let value = rowData[header];
            // undefined や null は空文字に
            if (value === undefined || value === null) {
                return "";
            }
            // 文字列内のカンマや改行、ダブルクォートをエスケープ
            value = String(value);
            if (value.includes(",") || value.includes("n") || value.includes(""")) {
                value = `"${value.replace(/"/g, """")}"`;
            }
            return value;
        });
        csvContent += row.join(",") + "n";
    });

    try {
        fs.writeFileSync(filename, csvContent, "utf-8");
        console.log(`記事データを ${filename} にエクスポートしました。`);
    } catch (error) {
        console.error(`ファイル書き込み中にエラーが発生しました (${filename}):`, error);
    }
}

// --- メイン処理 ---
async function main() {
    if ([NEWT_SPACE_UID, NEWT_APP_UID, NEWT_MODEL_UID, NEWT_API_TOKEN].some(val => val.startsWith("YOUR_"))) {
        console.error("エラー: スクリプト内の設定項目(SPACE_UID, APP_UID, MODEL_UID, API_TOKEN)を実際の値に置き換えてください。");
        return;
    }

    const articles = await fetchAllNewsArticles();

    if (articles) {
        // CSV形式でエクスポート
        exportToCsv(articles, OUTPUT_CSV_FILE);
    }
}

main();

取得した SPACE_UID,APP_UID,MODEL_UID,YOUR_API_TOKEN をそれぞれ設定項目に指定をします。

コード実行

その中でターミナルまたはコマンドプロンプトで以下のコマンドをを実行すると、スクリプトと同階層に「{NEWT_MODEL_UID}_export.csv」が作成されます。

node export_news_articles.js

NILTOへのコンテンツインポート手順

出力された「{NEWT_MODEL_UID}_export.csv」の内容をインポートする手順は以下になります

CSVインポート

コンテンツ一覧画面の右メニューで「CSVエクスポート」を選択し、「{NEWT_MODEL_UID}_export.csv」を選択します。

インポート後、対象のモデルに下書き状態で追加され、下書きから公開に関しては個別に行います。

フロントエンド(Astro)のデータ取得先をNewtからNILTOへ変更する手順

データ移行後の Newt から NILTO への API 経由でのニュース記事一覧データ取得の変更前後のコードは以下のようになります。

---

const spaceUid = import.meta.env.NEWT_SPACE_UID;
const appUid = import.meta.env.NEWT_APP_UID;
const modelUid = import.meta.env.NEWT_MODEL_UID_NEWS;
const token = import.meta.env.NEWT_CDN_API_TOKEN;

// Newt APIから記事一覧を取得
const response = await fetch(  `https://${spaceUid}.newt.so/api/v1/${appUid}/${modelUid}?order=_publishedAt`, // appUid, modelUid は実際の値に
  {
    headers: {
      Authorization: `Bearer ${token}`,
    },
  }
);

let articles = [];
if (response.ok) {
  const data = await response.json();
  articles = data.items; // レスポンス構造に合わせて調整
} else {
  console.error("Failed to fetch articles from Newt:", await response.text());
}
---

~~~ フロントエンドコード 

上記のコードを仮定した上で、NILTO への変更後のコードは下記になります。

---

const apiKey = import.meta.env.NILTO_API_KEY;
const modelluId = import.meta.env.NILTO_NEWS_MODEL_LUID; // NILTOでのモデル識別子

// NILTO APIから記事一覧を取得
const response = await fetch(
  `https://cms-api.nilto.com/v1/contents?model=${modelluId }&order=_publishedAt`, // 仮のエンドポイントとパラメータ
  {
    headers: {
      "X-NILTO-API-KEY": apiKey    },
  }
);

let articles = [];
if (response.ok) {
  const data = await response.json();
  articles = data.data;
} else {
  console.error("Failed to fetch articles from NILTO:", await response.text());
}

---

~~~ フロントエンドコード 

注意点

Form AppはNILTOに同等機能がないため対象外となっています。Form App の代わりにHubSpotのフォーム機能、formrunなどをご検討ください。

さいごに

Newtサービス終了に伴い、移行先としてNILTOの紹介をしました。文頭で書いているように、移行手順で使用しているNILTOのCSVインポート機能は、ビジネスプラン以上でご利用いただけます。14日間の無料トライアルをご用意していますのでぜひご利用ください。
無料トライアル期間中であれば、移行後にパーソナルプランに戻すことで費用は発生せずにご利用いただけます。

問題は解決しましたか?

回答が見つからない場合は、お問合せのサポート窓口からお気軽にお問いあわせください。

お問い合わせ