teachyou.ai academy
← All posts
LangChain

LangChain Community vs Core: Understanding the Package Split

Pramod Dutta · Jul 1, 2026 · 12 min read

Why This Question Keeps Coming Up

If you have spent any time building with LangChain over the past couple of years, you have almost certainly hit an import error that used to work and suddenly does not. You upgrade a package, run your script, and get hit with a ModuleNotFoundError pointing at something like langchain.chat_models or langchain.vectorstores. The fix usually involves changing one import line to pull from langchain_community instead, and everything works again. But most developers never stop to ask why this happened in the first place, and that gap in understanding is exactly what causes repeated confusion every time LangChain ships a new release.

The short version is that LangChain used to be one large package that tried to do everything: core abstractions, integrations with hundreds of third-party tools, agent logic, memory, chains, and more. As the ecosystem grew, that single package became slow to install, hard to version, and fragile to maintain. The maintainers split it apart, and langchain-core and langchain-community are the two pieces developers run into most often. Understanding what belongs in each, why the boundary exists, and how to import correctly will save you hours of debugging and make your applications far more resilient to future changes.

This article walks through the actual architecture, not just the surface-level "put your imports here" advice. By the end you will understand the dependency graph, know how to structure your own code to avoid breakage, and see working examples of the split in action.

The Problem With One Giant Package

Before the split, langchain was a monolith. Installing it meant pulling in optional dependencies for OpenAI, Anthropic, Pinecone, FAISS, Elasticsearch, Google, AWS, and dozens of other providers, even if your project only used one or two of them. This created several real problems that the maintainers had to solve:

  • Dependency bloat. A simple project using only OpenAI's chat models still triggered installs or import attempts related to vector databases, document loaders, and cloud SDKs it never touched.
  • Version conflicts. Third-party SDKs update on their own schedules. If langchain bundled a specific version requirement for, say, boto3 or google-cloud-aiplatform, it could easily collide with what the rest of your project needed.
  • Slow release cycles. Every time a partner integration needed a fix, the entire langchain package had to be versioned and released, even though the core abstractions had not changed at all.
  • Unclear stability guarantees. Core abstractions like Runnable, prompt templates, and output parsers are meant to be stable contracts that other code depends on. Community-contributed integrations are inherently more volatile because they track external APIs that change without warning. Mixing both in one package made it impossible to communicate which parts were safe to build on.

The fix was to separate the stable foundation from the fast-moving, community-maintained integrations. That gave us the current multi-package structure.

What Lives in langchain-core

langchain-core is the foundation. It contains the abstract base classes and interfaces that everything else in the ecosystem builds on top of. If you strip LangChain down to its essential ideas, this is the package that holds them.

Specifically, langchain-core includes:

  • The Runnable interface — the protocol that powers LangChain Expression Language (LCEL), including invoke, batch, stream, and their async counterparts.
  • Prompt templatesPromptTemplate, ChatPromptTemplate, and the message classes like HumanMessage, AIMessage, and SystemMessage.
  • Output parsers — the base classes for parsing LLM output into structured formats.
  • Base classes for models — abstract definitions like BaseChatModel and BaseLLM that concrete provider implementations must satisfy.
  • Document and retriever abstractions — the Document class and the BaseRetriever interface.
  • Tracing and callback interfaces — the hooks that let tools like LangSmith observe what is happening inside a chain.

Notice what is missing from that list: no OpenAI client, no Pinecone connector, no PDF loader. langchain-core deliberately has almost no third-party dependencies. It is designed to be small, stable, and safe to import without dragging in unrelated SDKs.

Here is a simple example that uses nothing but langchain-core concepts:

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnableLambda

prompt = ChatPromptTemplate.from_messages([
    ("system", "You are a concise technical writer."),
    ("human", "Summarize this in one sentence: {text}")
])

uppercase_step = RunnableLambda(lambda x: x.upper())

# This chain only depends on langchain-core abstractions
partial_chain = prompt | uppercase_step

That code will not actually call a model, because no model is wired in yet, but it demonstrates that prompts, runnables, and the piping syntax (|) all live in langchain-core. You could swap in any chat model later without changing this foundation.

What Lives in langchain-community

langchain-community is where the actual integrations live. This is the package that contains implementations for the hundreds of vector stores, document loaders, embedding providers, tool wrappers, and utility classes that make LangChain useful in practice rather than just theoretical.

Things you will find in langchain-community:

  • Document loaders for PDFs, Notion, Slack exports, Google Drive, web pages, and dozens of other sources.
  • Vector store integrations for FAISS, Chroma (community-maintained versions), Weaviate, Qdrant, and many others.
  • Utility wrappers for search APIs, calculators, and other tool implementations that agents can call.
  • Legacy chat model and embedding classes for providers that have not yet moved to their own dedicated package.
  • Community-maintained tools contributed by the open-source community, with varying levels of testing and long-term support.

The key distinguishing feature of langchain-community is that it depends on external SDKs. Importing a class from this package can trigger an import of boto3, google-cloud-storage, pypdf, or whatever the underlying integration needs. Because those dependencies are optional, LangChain uses lazy imports inside langchain-community so that installing the package does not force you to install every third-party SDK it wraps. You only need the specific SDK for the integration you actually use.

Here is an example showing a community document loader:

from langchain_community.document_loaders import PyPDFLoader

loader = PyPDFLoader("company_handbook.pdf")
pages = loader.load()

print(f"Loaded {len(pages)} pages")
print(pages[0].page_content[:200])

This import requires pypdf to be installed separately. If it is missing, you get a clear error telling you exactly which package to add, rather than a bloated install pulling in dependencies you never asked for.

The Partner Packages: A Third Category

There is actually a third tier that many tutorials skip over: dedicated partner packages like langchain-openai, langchain-anthropic, langchain-google-genai, and langchain-pinecone. These are separate from both langchain-core and langchain-community.

Why do these exist as their own packages instead of living in langchain-community? Because high-traffic integrations benefit from tighter maintenance, dedicated versioning, and closer collaboration with the provider. Instead of a community-contributed wrapper that might lag behind API changes, langchain-openai is maintained with a much shorter feedback loop and is treated as production-grade.

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

model = ChatOpenAI(model="gpt-4o-mini", temperature=0)

prompt = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful assistant."),
    ("human", "{question}")
])

chain = prompt | model | StrOutputParser()

response = chain.invoke({"question": "What is the boiling point of water at sea level?"})
print(response)

Notice the pattern: langchain_core supplies the prompt template, the runnable piping syntax, and the output parser base classes. langchain_openai supplies the actual model implementation. Nothing here touches langchain_community at all, because OpenAI graduated out of the community package once it got its own dedicated home.

The general rule of thumb: if a provider is popular enough and well-resourced enough to maintain a dedicated package, it usually has one. Everything else, especially long-tail integrations and utilities, lives in langchain-community.

How the Dependency Graph Actually Works

Understanding the direction of dependencies makes the whole system click. It works like this:

  1. langchain-core has almost no dependencies on anything else in the ecosystem. It is the base layer.
  2. langchain-community depends on langchain-core for its abstractions, plus whatever third-party SDKs each specific integration needs.
  3. Partner packages like langchain-openai also depend on langchain-core, plus the specific provider SDK (like the openai Python package).
  4. The top-level langchain package depends on langchain-core and, historically, re-exported things from langchain-community for backward compatibility. In recent versions, langchain itself has been slimmed down to focus on chains, agents, and retrieval logic that orchestrate the pieces below it.

This means langchain-core never imports from langchain-community, and that is intentional. If core depended on community, you would be back to the original bloat problem, just with different package names. The dependency arrow only ever points one direction: outward packages depend on core, never the reverse.

You can verify this yourself:

import langchain_core
import os

# langchain-core has a minimal dependency footprint
core_path = os.path.dirname(langchain_core.__file__)
print(f"langchain-core location: {core_path}")

# Compare installed sizes to see the difference in scope

If you inspect the pyproject.toml or setup.py of langchain-core on GitHub, you will see it lists almost nothing beyond pydantic, typing-extensions, and a couple of small utility libraries. Compare that to langchain-community, whose dependency list is enormous because it has to accommodate every integration it ships, even as optional extras.

Practical Import Rules to Follow

Once you internalize the split, a few practical rules make your codebase much more maintainable:

  • Import base abstractions from `langchain_core`. Prompt templates, message types, output parsers, and the Runnable interface should always come from langchain_core, not from langchain directly. This protects you from deprecation warnings in newer versions.
  • Import specific model providers from their dedicated package when one exists. Use langchain_openai, langchain_anthropic, langchain_google_genai, or similar, rather than pulling generic classes from langchain_community if a dedicated package is available. Dedicated packages get faster bug fixes and better long-term support.
  • Fall back to `langchain_community` for long-tail integrations. Document loaders for niche file formats, less common vector stores, and community tools will usually only exist here. That is fine, just be aware that stability guarantees are looser.
  • Pin your versions. Because these are now separate packages with independent release cycles, it is worth pinning langchain-core, langchain-community, and any partner packages to compatible versions in your requirements.txt or pyproject.toml, rather than letting them drift independently.
  • Check the deprecation warnings. LangChain is good about issuing DeprecationWarning messages when you import something from a legacy path. Do not ignore these. They usually tell you exactly which new import path to switch to.

Here is what a clean, modern set of imports typically looks like in a real project:

# Core abstractions - stable, minimal dependencies
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.messages import HumanMessage, SystemMessage
from langchain_core.output_parsers import JsonOutputParser
from langchain_core.runnables import RunnablePassthrough

# Dedicated provider package - production-grade integration
from langchain_openai import ChatOpenAI, OpenAIEmbeddings

# Community package - long-tail integrations
from langchain_community.vectorstores import FAISS
from langchain_community.document_loaders import WebBaseLoader

model = ChatOpenAI(model="gpt-4o-mini")
embeddings = OpenAIEmbeddings()

loader = WebBaseLoader("https://example.com/article")
docs = loader.load()

vectorstore = FAISS.from_documents(docs, embeddings)
retriever = vectorstore.as_retriever()

chain = (
    {"context": retriever, "question": RunnablePassthrough()}
    | ChatPromptTemplate.from_template(
        "Answer using only this context:\n{context}\n\nQuestion: {question}"
    )
    | model
    | JsonOutputParser()
)

This snippet cleanly shows all three tiers working together: core abstractions provide the plumbing, the dedicated OpenAI package provides the model and embeddings, and the community package provides the web loader and FAISS vector store. Each piece comes from exactly where it should.

Common Migration Mistakes

Developers coming from older LangChain tutorials or courses run into a predictable set of mistakes when the package split trips them up:

  • Importing everything from `langchain` directly. Older code often does from langchain.chat_models import ChatOpenAI or from langchain.vectorstores import FAISS. These paths still sometimes work through backward-compatible shims, but they are deprecated and will eventually be removed. Update them to the specific package.
  • Installing `langchain` and expecting integrations to work automatically. Many developers are surprised that pip install langchain does not give them working PDF loaders or vector store connectors. You need langchain-community explicitly, plus whatever underlying SDK the specific loader or store requires.
  • Mixing versions that were never tested together. Because langchain-core, langchain-community, and partner packages version independently, it is possible to end up with combinations that were never actually tested together upstream. If you hit a strange error after an upgrade, check whether your langchain-core version is compatible with your installed langchain-community and partner package versions.
  • Not reading the error message closely. LangChain's import errors are usually quite informative now. They typically tell you the exact new import path or the exact missing dependency to install. Resist the urge to guess; read the full traceback.
  • Forgetting that community integrations can be inconsistent in quality. Since anyone can contribute to langchain-community, quality and maintenance levels vary. If you hit a bug in a community integration, check whether a dedicated partner package exists as an alternative before assuming the feature is broken.

Why This Design Will Keep Evolving

It is worth setting expectations here: this three-tier structure is not the final form of LangChain's architecture, it is a snapshot of an ecosystem that is still actively reorganizing itself. Integrations continue to graduate out of langchain-community into their own dedicated packages as they gain enough usage to justify it. The maintainers have been fairly transparent that the long-term goal is for langchain-community to shrink over time as more integrations "graduate," while langchain-core stays intentionally small and stable.

This matters practically because code you write today assuming an integration lives in langchain-community might need an import update in six months when that integration gets its own package. The good news is that the underlying class names and interfaces tend to stay consistent even when the import path changes, because everything still implements the same langchain-core abstractions. A BaseChatModel is a BaseChatModel whether it ships from langchain-community or a dedicated partner package, and code written against the abstraction rather than the concrete import path tends to survive these moves with minimal changes.

Bringing It All Together

The community versus core split is not an arbitrary organizational choice, it reflects a real architectural principle: separate the stable, dependency-light foundation from the fast-moving, dependency-heavy integrations. langchain-core gives you the contracts, langchain-community gives you the breadth of integrations, and dedicated partner packages give you production-grade implementations for the most widely used providers. Once you see the ecosystem through that lens, import errors stop being mysterious and start being predictable: check which tier the class belongs to, and import from the right place.

If you want to go beyond reading about this and actually build production-ready chains, agents, and retrieval pipelines with the current package structure, hands-on practice makes the difference. Our LangChain Tutorial 2026 course on teachyou.ai walks through this exact architecture in depth, with real projects that use langchain-core, langchain-community, and the dedicated provider packages together, so you build the muscle memory for structuring imports correctly from day one instead of learning it through trial and error.